{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:56:55.748173Z",
     "start_time": "2022-05-10T07:56:55.732138Z"
    }
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.models import Model\n",
    "from tensorflow.keras.layers import Embedding, LSTM, Dense, Input, Attention,Concatenate,Dropout,Conv1D, MaxPool1D, Flatten\n",
    "from tensorflow.keras.preprocessing.sequence import pad_sequences\n",
    "from tensorflow.keras.callbacks import ModelCheckpoint\n",
    "from tensorflow.keras.utils import plot_model\n",
    "from tensorflow.keras.optimizers import RMSprop\n",
    "import tensorflow as tf\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文本预处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:00.715090Z",
     "start_time": "2022-05-10T07:57:00.687448Z"
    }
   },
   "outputs": [],
   "source": [
    "import jieba\n",
    "import os\n",
    "import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:00.947840Z",
     "start_time": "2022-05-10T07:57:00.911164Z"
    }
   },
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: 'NLPIR_stopwords.txt'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_15452/2935734785.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m#导入停用词\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mstop_words\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'NLPIR_stopwords.txt'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'r'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mencoding\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'utf-8'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msplit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'\\n'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[1;31m# 为语料做分词处理\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mword_segment\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'NLPIR_stopwords.txt'"
     ]
    }
   ],
   "source": [
    "#导入停用词\n",
    "stop_words = open('NLPIR_stopwords.txt','r',encoding='utf-8').read().split('\\n')\n",
    "\n",
    "# 为语料做分词处理\n",
    "def word_segment():\n",
    "    # 打开语料文本\n",
    "    inputFile_NoSegment = open(os.getcwd() + '/对话内容/chatterbot.tsv', 'r', encoding='utf-8')#文本格式读取\n",
    "    # 处理过的文本存档\n",
    "    outputFile_Segment = open(os.getcwd() + '/对话内容/chatterbot.txt','w', encoding='utf-8')\n",
    "    # 列表读取语料文本中的每一行文字 \n",
    "    lines = inputFile_NoSegment.readlines()\n",
    "    \n",
    "    # 为每一行文字分词\n",
    "    for i in range(len(lines)):\n",
    "        line = lines[i]\n",
    "        if line:\n",
    "            line = line.strip()\n",
    "            \n",
    "            line=re.sub('[\\\\\\'!\"#$%&\\'()*+,-./:;<=>?@，。?★、…【】《》？“”‘\\\\\\'！[\\\\]^_`{|}~]+','',line)#正则去除特殊字符\n",
    "            line=re.sub('\\t|\\n|\\s|\\r',' ',line)#正则清洗多余换行空格\n",
    "            line=re.sub('\\s+',' ',line)\n",
    "            \n",
    "            seg_list = jieba.cut(line)#分词\n",
    "\n",
    "            segments = ''\n",
    "            for word in seg_list:\n",
    "                #if word not in stop_words:#去停用词\n",
    "                segments = segments + ' ' + word\n",
    "            segments += '\\n'\n",
    "            segments = segments.lstrip()\n",
    "\n",
    "            # 将分词后的语句，写进文件中\n",
    "            outputFile_Segment.write(segments)\n",
    "\n",
    "    inputFile_NoSegment.close()\n",
    "    outputFile_Segment.close()\n",
    "\n",
    "word_segment()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:01.508545Z",
     "start_time": "2022-05-10T07:57:01.344478Z"
    }
   },
   "outputs": [],
   "source": [
    "# 处理过的文本存档\n",
    "outputFile_Segment = open(os.getcwd() + '/对话内容/clean_conversation_2.txt','w', encoding='utf-8')\n",
    "with open(os.getcwd() + '/对话内容/clean_conversation.txt', 'r', encoding='utf-8') as f:\n",
    "    lines = f.read().split('\\n')\n",
    "for line in lines[: min(600, len(lines) - 1)]:\n",
    "    input_t = line.split('\\t')[0]\n",
    "    target_t = line.split('\\t')[1]\n",
    "    input_t=re.sub('[\\\\\\'!\"#$%&\\'()*+,-./:;<=>?@，。?★、…【】《》？“”‘\\\\\\'！[\\\\]^_`{|}~]+','',input_t)#正则去除特殊字符\n",
    "    input_t=re.sub('\\t|\\n|\\s|\\r',' ',input_t)#正则清洗多余换行空格\n",
    "    input_t=re.sub('\\s+',' ',input_t)\n",
    "    target_t=re.sub('[\\\\\\'!\"#$%&\\'()*+,-./:;<=>?@，。?★、…【】《》？“”‘\\\\\\'！[\\\\]^_`{|}~]+','',target_t)#正则去除特殊字符\n",
    "    target_t=re.sub('\\t|\\n|\\s|\\r',' ',target_t)#正则清洗多余换行空格\n",
    "    target_t=re.sub('\\s+',' ',target_t)\n",
    "    outputFile_Segment.write((input_t + '\\n').lstrip())\n",
    "    outputFile_Segment.write((target_t+ '\\n').lstrip())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文本导入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:06.106831Z",
     "start_time": "2022-05-10T07:57:06.086292Z"
    },
    "jupyter": {
     "outputs_hidden": true
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "对话内容总数： 3654\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "# 读取处理过的文本\n",
    "text_Segment = open(os.getcwd() + '/对话内容/Source_segment.txt','r', encoding='utf-8')\n",
    "text_Segment_list = text_Segment.readlines()\n",
    "text_Segment.close()\n",
    "# 移除换行\n",
    "text_Segment_list = [n.rstrip() for n in text_Segment_list]\n",
    "if len(text_Segment_list)%2!=0:\n",
    "    print(\"文本库数据有误 对话不对称 请检查！\")\n",
    "else:\n",
    "    print('对话内容总数：', len(text_Segment_list))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:06.623919Z",
     "start_time": "2022-05-10T07:57:06.602973Z"
    }
   },
   "outputs": [],
   "source": [
    "from collections import Counter\n",
    "\n",
    "#<PAD>填充句子\n",
    "#<UNK>替换词汇表里不存在的字符\n",
    "#<GO>句子输入的开始, 即第一个时间步长的输入\n",
    "#<EOS>句子输入的结束.\n",
    "\n",
    "def fit_text(X, Y, input_seq_max_length=None, target_seq_max_length=None):\n",
    "    if input_seq_max_length is None:\n",
    "        input_seq_max_length = MAX_INPUT_SEQ_LENGTH\n",
    "    if target_seq_max_length is None:\n",
    "        target_seq_max_length = MAX_TARGET_SEQ_LENGTH\n",
    "    input_counter = Counter()\n",
    "    target_counter = Counter()\n",
    "    max_input_seq_length = 0\n",
    "    max_target_seq_length = 0\n",
    "\n",
    "    for line in X:\n",
    "        text = [word.lower() for word in line.split(' ')]\n",
    "        seq_length = len(text)\n",
    "        if seq_length > input_seq_max_length:\n",
    "            text = text[0:input_seq_max_length]\n",
    "            seq_length = len(text)\n",
    "        for word in text:\n",
    "            input_counter[word] += 1\n",
    "        max_input_seq_length = max(max_input_seq_length, seq_length)\n",
    "\n",
    "    for line in Y:\n",
    "        line2 = 'START ' + line.lower() + ' END'\n",
    "        text = [word for word in line2.split(' ')]\n",
    "        seq_length = len(text)\n",
    "        if seq_length > target_seq_max_length:\n",
    "            text = text[0:target_seq_max_length]\n",
    "            seq_length = len(text)\n",
    "        for word in text:\n",
    "            target_counter[word] += 1\n",
    "            max_target_seq_length = max(max_target_seq_length, seq_length)\n",
    "\n",
    "    input_word2idx = dict()\n",
    "    for idx, word in enumerate(input_counter.most_common(MAX_INPUT_VOCAB_SIZE)):\n",
    "        input_word2idx[word[0]] = idx + 2\n",
    "    input_word2idx['PAD'] = 0\n",
    "    input_word2idx['UNK'] = 1\n",
    "    input_idx2word = dict([(idx, word) for word, idx in input_word2idx.items()])\n",
    "\n",
    "    target_word2idx = dict()\n",
    "    for idx, word in enumerate(target_counter.most_common(MAX_TARGET_VOCAB_SIZE)):\n",
    "        target_word2idx[word[0]] = idx + 1\n",
    "    target_word2idx['UNK'] = 0\n",
    "\n",
    "    target_idx2word = dict([(idx, word) for word, idx in target_word2idx.items()])\n",
    "    \n",
    "    num_input_tokens = len(input_word2idx)\n",
    "    num_target_tokens = len(target_word2idx)\n",
    "    #词向量\n",
    "    config = dict()\n",
    "    config['input_word2idx'] = input_word2idx\n",
    "    config['input_idx2word'] = input_idx2word\n",
    "    config['target_word2idx'] = target_word2idx\n",
    "    config['target_idx2word'] = target_idx2word\n",
    "    config['num_input_tokens'] = num_input_tokens\n",
    "    config['num_target_tokens'] = num_target_tokens\n",
    "    config['max_input_seq_length'] = max_input_seq_length\n",
    "    config['max_target_seq_length'] = max_target_seq_length\n",
    "\n",
    "    return config"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-06T12:48:30.037407Z",
     "start_time": "2022-05-06T12:48:30.016466Z"
    }
   },
   "source": [
    "* ### Seq2Seq模型框架  \n",
    "![model](./reports/model.png)\n",
    "    \n",
    "    \n",
    "* ### encoder端  \n",
    "![encoder](./reports/self.encoder_model.png)\n",
    "    \n",
    "    \n",
    "* ### decoder端 \n",
    "![decoder](./reports/self.decoder_model.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Seq2Seq模型（生成器）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模型配置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:08.349511Z",
     "start_time": "2022-05-10T07:57:08.333543Z"
    }
   },
   "outputs": [],
   "source": [
    "MAX_INPUT_SEQ_LENGTH = 14 # 编码器输入长度\n",
    "MAX_TARGET_SEQ_LENGTH = 20 # 解码器输出长度\n",
    "MAX_INPUT_VOCAB_SIZE = 5000# 编码器词向量大小\n",
    "MAX_TARGET_VOCAB_SIZE = 5000 # 解码器词向量大小\n",
    "HIDDEN_UNITS = 188 #隐藏层s\n",
    "DEFAULT_BATCH_SIZE = 64 #批次（若文本量较小 需要降低）\n",
    "VERBOSE = 1 #日志\n",
    "USER_EPOCHS = 400 #自定义轮数\n",
    "DEFAULT_EPOCHS = 10 #默认轮数\n",
    "LEARNING_RATE = 0.001 #学习率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:09.546680Z",
     "start_time": "2022-05-10T07:57:09.523671Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num_input_tokens:  1379\n",
      "num_target_tokens:  2485\n",
      "max_input_seq_length:  14\n",
      "max_target_seq_length:  20\n"
     ]
    }
   ],
   "source": [
    "X = text_Segment_list[0:][::2] # 输入问句\n",
    "Y = text_Segment_list[1:][::2] # 输出答句\n",
    "config = fit_text(X, Y)\n",
    "\n",
    "print('num_input_tokens: ', config['num_input_tokens'])\n",
    "print('num_target_tokens: ', config['num_target_tokens'])\n",
    "print('max_input_seq_length: ', config['max_input_seq_length'])\n",
    "print('max_target_seq_length: ', config['max_target_seq_length'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T14:49:37.546210Z",
     "start_time": "2022-05-09T14:49:37.495566Z"
    }
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "import os\n",
    "\n",
    "class Seq2SeqSummarizer(object):\n",
    "\n",
    "    model_name = 'seq2seq'\n",
    "\n",
    "    def __init__(self, config):\n",
    "        #Seq2Seq模型定义\n",
    "        self.num_input_tokens = config['num_input_tokens']\n",
    "        self.max_input_seq_length = config['max_input_seq_length']\n",
    "        self.num_target_tokens = config['num_target_tokens']\n",
    "        self.max_target_seq_length = config['max_target_seq_length']\n",
    "        self.input_word2idx = config['input_word2idx']\n",
    "        self.input_idx2word = config['input_idx2word']\n",
    "        self.target_word2idx = config['target_word2idx']\n",
    "        self.target_idx2word = config['target_idx2word']\n",
    "        self.config = config\n",
    "\n",
    "        self.version = 0\n",
    "        if 'version' in config:\n",
    "            self.version = config['version']\n",
    "        #编码器\n",
    "        encoder_inputs = Input(shape=(None,), name='encoder_inputs')\n",
    "        encoder_embedding = Embedding(input_dim=self.num_input_tokens, # 词汇表大小\n",
    "                                      output_dim=HIDDEN_UNITS, # 词向量维度\n",
    "                                      input_length=self.max_input_seq_length, # 输入序列的长度\n",
    "                                      name='encoder_embedding')\n",
    "        encoder_lstm = LSTM(units=HIDDEN_UNITS, return_state=True, name='encoder_lstm')\n",
    "        encoder_outputs, encoder_state_h, encoder_state_c = encoder_lstm(encoder_embedding(encoder_inputs))\n",
    "        \n",
    "        encoder_states = [encoder_state_h, encoder_state_c]\n",
    "        #解码器\n",
    "        decoder_inputs = Input(shape=(None, self.num_target_tokens), name='decoder_inputs')\n",
    "        decoder_lstm = LSTM(units=HIDDEN_UNITS, return_state=True, return_sequences=True, name='decoder_lstm')\n",
    "        decoder_outputs, decoder_state_h, decoder_state_c = decoder_lstm(decoder_inputs,\n",
    "                                                                         initial_state=encoder_states)\n",
    "        \n",
    "        #注意力层\n",
    "        attention = Attention(name='attention_layer')\n",
    "        attention_output = attention([decoder_outputs,encoder_outputs])\n",
    "        \n",
    "        decoder_concat = Concatenate(axis=-1, name='concat_layer')\n",
    "        decoder_concat_input = decoder_concat([decoder_outputs, attention_output])\n",
    "        #随机失活\n",
    "        #decoder_dropout = Dropout(0.2)\n",
    "        #decoder_concat_input = decoder_dropout(decoder_concat_input)\n",
    "        decoder_dense = Dense(units=self.num_target_tokens, activation='softmax', name='decoder_dense')\n",
    "        \n",
    "        decoder_outputs = decoder_dense(decoder_concat_input)\n",
    "\n",
    "        model = Model([encoder_inputs, decoder_inputs], decoder_outputs)\n",
    "        plot_model(model, to_file='./reports/model.png',show_shapes=True)\n",
    "        \n",
    "        #模型训练\n",
    "        #model.compile(loss='categorical_crossentropy', optimizer=RMSprop(lr=LEARNING_RATE), metrics=['accuracy'])\n",
    "        model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "\n",
    "        #单独定义编码器解码器 便于预测时使用\n",
    "        self.model = model\n",
    "        #编码器模型输出和隐藏层码\n",
    "        self.encoder_model = Model(encoder_inputs,[encoder_outputs,encoder_states])\n",
    "        #self.encoder_model = Model(encoder_inputs,encoder_states)\n",
    "        plot_model(self.encoder_model, to_file='./reports/self.encoder_model.png',show_shapes=True)\n",
    "\n",
    "        decoder_state_inputs = [Input(shape=(HIDDEN_UNITS,)), Input(shape=(HIDDEN_UNITS,))]\n",
    "        decoder_outputs, state_h, state_c = decoder_lstm(decoder_inputs, initial_state=decoder_state_inputs)\n",
    "        decoder_states = [state_h, state_c]\n",
    "        #注意力层\n",
    "        attention_output  = attention([decoder_outputs,encoder_outputs])\n",
    "        decoder_concat_input = decoder_concat([decoder_outputs, attention_output])\n",
    "        #decoder_concat_input = decoder_dropout(decoder_concat_input)\n",
    "        decoder_outputs = decoder_dense(decoder_concat_input)\n",
    "        #解码器输出预测\n",
    "        self.decoder_model = Model([decoder_inputs,encoder_outputs] + decoder_state_inputs, [decoder_outputs] + decoder_states)\n",
    "        self.decoder_model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "\n",
    "        plot_model(self.decoder_model, to_file='./reports/self.decoder_model.png',show_shapes=True)\n",
    "\n",
    "        #加载权重\n",
    "    def load_weights(self, weight_file_path,decoder_weight_file_path):\n",
    "        if os.path.exists(weight_file_path):\n",
    "            self.model.load_weights(weight_file_path)\n",
    "            self.decoder_model.load_weights(decoder_weight_file_path)\n",
    "    \n",
    "    #将输入的文本转换为词向量\n",
    "    def transform_input_text(self, texts):\n",
    "        temp = []\n",
    "        for line in texts:\n",
    "            x = []\n",
    "            for word in line.lower().split(' '):\n",
    "                wid = 1\n",
    "                if word in self.input_word2idx:\n",
    "                    wid = self.input_word2idx[word]\n",
    "                x.append(wid)\n",
    "                if len(x) >= self.max_input_seq_length:\n",
    "                    break\n",
    "            temp.append(x)\n",
    "        temp = pad_sequences(temp, maxlen=self.max_input_seq_length)\n",
    "\n",
    "        print(temp.shape)\n",
    "        return temp\n",
    "    \n",
    "    #辨别器数据向量化\n",
    "    def tokenize(self, texts):\n",
    "        temp = []\n",
    "        for line in texts:\n",
    "            x = []\n",
    "            for word in line.lower().split(' '):\n",
    "                wid = 1\n",
    "                if word in self.input_word2idx:\n",
    "                    wid = self.input_word2idx[word]\n",
    "                x.append(wid)\n",
    "                if len(x) >= self.max_target_seq_length:\n",
    "                    break\n",
    "            temp.append(x)\n",
    "        temp = pad_sequences(temp, maxlen=self.max_target_seq_length)\n",
    "\n",
    "        print(temp.shape)\n",
    "        return temp\n",
    "    \n",
    "    #增加开始结束标签\n",
    "    def transform_target_encoding(self, texts):\n",
    "        temp = []\n",
    "        for line in texts:\n",
    "            x = []\n",
    "            line2 = 'START ' + line.lower() + ' END'\n",
    "            for word in line2.split(' '):\n",
    "                if len(x) >= self.max_target_seq_length:\n",
    "                    x[self.max_target_seq_length-1] = 'END'\n",
    "                    break\n",
    "                x.append(word)\n",
    "            temp.append(x)\n",
    "\n",
    "        temp = np.array(temp)\n",
    "        print(temp.shape)\n",
    "        return temp\n",
    "\n",
    "    #批次训练\n",
    "    def generate_batch(self, x_samples, y_samples, batch_size):\n",
    "        num_batches = len(x_samples) // batch_size\n",
    "        while True:\n",
    "            for batchIdx in range(0, num_batches):\n",
    "                start = batchIdx * batch_size\n",
    "                end = (batchIdx + 1) * batch_size\n",
    "                encoder_input_data_batch = pad_sequences(x_samples[start:end], self.max_input_seq_length)\n",
    "                decoder_target_data_batch = np.zeros(shape=(batch_size, self.max_target_seq_length, self.num_target_tokens))\n",
    "                decoder_input_data_batch = np.zeros(shape=(batch_size, self.max_target_seq_length, self.num_target_tokens))\n",
    "                for lineIdx, target_words in enumerate(y_samples[start:end]):\n",
    "                    for idx, w in enumerate(target_words):\n",
    "                        w2idx = 0  # default [UNK]\n",
    "                        if w in self.target_word2idx:\n",
    "                            w2idx = self.target_word2idx[w]\n",
    "                        if w2idx != 0:\n",
    "                            decoder_input_data_batch[lineIdx, idx, w2idx] = 1\n",
    "                            if idx > 0:\n",
    "                                decoder_target_data_batch[lineIdx, idx - 1, w2idx] = 1\n",
    "                yield [encoder_input_data_batch, decoder_input_data_batch], decoder_target_data_batch\n",
    "    def generate_batch2(x_samples, y_samples, batch_size = 64,num_batches=1):\n",
    "        self = summarizer\n",
    "        start = 0\n",
    "        end = batch_size\n",
    "        encoder_input_data_batch = pad_sequences(x_samples[start:end], summarizer.max_input_seq_length)\n",
    "        decoder_target_data_batch = np.zeros(shape=(batch_size, summarizer.max_target_seq_length, summarizer.num_target_tokens))\n",
    "        decoder_input_data_batch = np.zeros(shape=(batch_size, summarizer.max_target_seq_length, summarizer.num_target_tokens))\n",
    "        for lineIdx, target_words in enumerate(y_samples[start:end]):\n",
    "            for idx, w in enumerate(target_words):\n",
    "                w2idx = 0  # default [UNK]\n",
    "                if w in self.target_word2idx:\n",
    "                    w2idx = self.target_word2idx[w]\n",
    "                if w2idx != 0:\n",
    "                    decoder_input_data_batch[lineIdx, idx, w2idx] = 1\n",
    "                    if idx > 0:\n",
    "                        decoder_target_data_batch[lineIdx, idx - 1, w2idx] = 1\n",
    "        return [encoder_input_data_batch, decoder_input_data_batch], decoder_target_data_batch\n",
    "    @staticmethod\n",
    "    def get_weight_file_path(model_dir_path):#权重\n",
    "        return model_dir_path + '/' + Seq2SeqSummarizer.model_name + '-weights.h5'\n",
    "    @staticmethod\n",
    "    def get_decoder_weight_file_path(model_dir_path):#权重\n",
    "        return model_dir_path + '/' + 'decoder-weights.h5'\n",
    "    @staticmethod\n",
    "    def get_config_file_path(model_dir_path):#配置\n",
    "        return model_dir_path + '/' + Seq2SeqSummarizer.model_name + '-config.npy'\n",
    "\n",
    "    @staticmethod\n",
    "    def get_architecture_file_path(model_dir_path):#结构\n",
    "        return model_dir_path + '/' + Seq2SeqSummarizer.model_name + '-architecture.json'\n",
    "\n",
    "    #预测\n",
    "    def fit(self, Xtrain, Ytrain, Xtest, Ytest, epochs=None, batch_size=None, model_dir_path=None):\n",
    "        if epochs is None:\n",
    "            epochs = DEFAULT_EPOCHS\n",
    "        if model_dir_path is None:\n",
    "            model_dir_path = './models'\n",
    "        if batch_size is None:\n",
    "            batch_size = DEFAULT_BATCH_SIZE\n",
    "\n",
    "        self.version += 1\n",
    "        self.config['version'] = self.version\n",
    "        #读取网络配置\n",
    "        config_file_path = Seq2SeqSummarizer.get_config_file_path(model_dir_path)\n",
    "        weight_file_path = Seq2SeqSummarizer.get_weight_file_path(model_dir_path)\n",
    "        decoder_weight_file_path = Seq2SeqSummarizer.get_decoder_weight_file_path(model_dir_path)\n",
    "        checkpoint = ModelCheckpoint(weight_file_path)\n",
    "        np.save(config_file_path, self.config)\n",
    "        architecture_file_path = Seq2SeqSummarizer.get_architecture_file_path(model_dir_path)\n",
    "        open(architecture_file_path, 'w').write(self.model.to_json())\n",
    "\n",
    "        Ytrain = self.transform_target_encoding(Ytrain)\n",
    "        Ytest = self.transform_target_encoding(Ytest)\n",
    "\n",
    "        Xtrain = self.transform_input_text(Xtrain)\n",
    "        Xtest = self.transform_input_text(Xtest)\n",
    "\n",
    "        train_gen = self.generate_batch(Xtrain, Ytrain, batch_size)\n",
    "        test_gen = self.generate_batch(Xtest, Ytest, batch_size)\n",
    "\n",
    "        train_num_batches = len(Xtrain) // batch_size\n",
    "        test_num_batches = len(Xtest) // batch_size\n",
    "\n",
    "        history = self.model.fit_generator(generator=train_gen, steps_per_epoch=train_num_batches,\n",
    "                                           epochs=epochs,\n",
    "                                           verbose=VERBOSE, validation_data=test_gen, validation_steps=test_num_batches,\n",
    "                                           callbacks=[checkpoint])\n",
    "        self.model.save_weights(weight_file_path)#保存模型权重\n",
    "        self.decoder_model.save_weights(decoder_weight_file_path)#保存模型权重\n",
    "        return history\n",
    "    \n",
    "    def summarize(self, input_text):\n",
    "        input_seq = []\n",
    "        input_wids = []\n",
    "        for word in input_text.lower().split(' '):\n",
    "            idx = 1  # default [UNK]\n",
    "            if word in self.input_word2idx:\n",
    "                idx = self.input_word2idx[word]\n",
    "            input_wids.append(idx)\n",
    "        input_seq.append(input_wids)\n",
    "        input_seq = pad_sequences(input_seq, self.max_input_seq_length)\n",
    "        encoder_outputs,states_value = self.encoder_model.predict(input_seq)\n",
    "        #states_value = self.encoder_model.predict(input_seq)\n",
    "        target_seq = np.zeros((1, 1, self.num_target_tokens))\n",
    "        target_seq[0, 0, self.target_word2idx['START']] = 1\n",
    "        target_text = ''\n",
    "        target_text_len = 0\n",
    "        terminated = False\n",
    "        while not terminated:\n",
    "            #print (target_seq.shape)\n",
    "            #print (np.array(states_value).shape)\n",
    "            output_tokens, h, c = self.decoder_model.predict([target_seq,encoder_outputs] + states_value)\n",
    "            #print (np.array(output_tokens).shape)\n",
    "            #print (np.array(h).shape)\n",
    "            #print (np.array(c).shape)\n",
    "\n",
    "            sample_token_idx = np.argmax(output_tokens[0, -1, :])\n",
    "            sample_word = self.target_idx2word[sample_token_idx]\n",
    "            target_text_len += 1\n",
    "\n",
    "            if sample_word != 'START' and sample_word != 'END':\n",
    "                target_text += ' ' + sample_word\n",
    "\n",
    "            if sample_word == 'END' or target_text_len >= self.max_target_seq_length:\n",
    "                terminated = True\n",
    "\n",
    "            target_seq = np.zeros((1, 1, self.num_target_tokens))\n",
    "            target_seq[0, 0, sample_token_idx] = 1\n",
    "\n",
    "            states_value = [h, c]\n",
    "        return target_text.strip()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "## 训练过程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T14:10:46.627111Z",
     "start_time": "2022-05-09T14:10:46.167076Z"
    },
    "code_folding": [],
    "hidden": true
   },
   "outputs": [],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "%notebook inline\n",
    "\n",
    "def create_history_plot(history, model_name, metrics=None):\n",
    "    plt.title('Accuracy and Loss (' + model_name + ')')\n",
    "    if metrics is None:\n",
    "        metrics = {'acc', 'loss'}\n",
    "    if 'acc' in metrics:\n",
    "        plt.plot(history.history['accuracy'], color='g', label='Train Accuracy')\n",
    "        plt.plot(history.history['val_accuracy'], color='b', label='Validation Accuracy')\n",
    "    if 'loss' in metrics:\n",
    "        plt.plot(history.history['loss'], color='r', label='Train Loss')\n",
    "        plt.plot(history.history['val_loss'], color='m', label='Validation Loss')\n",
    "    plt.legend(loc='best')\n",
    "\n",
    "    plt.tight_layout()\n",
    "\n",
    "\n",
    "def plot_history(history, model_name):\n",
    "    create_history_plot(history, model_name)\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "def plot_and_save_history(history, model_name, file_path, metrics=None):\n",
    "    if metrics is None:\n",
    "        metrics = {'acc', 'loss'}\n",
    "    create_history_plot(history, model_name, metrics)\n",
    "    plt.savefig(file_path)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T14:18:26.647473Z",
     "start_time": "2022-05-09T14:11:02.140225Z"
    },
    "hidden": true,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "training size:  1644\n",
      "testing size:  183\n",
      "start fitting ...\n",
      "(1644,)\n",
      "(183,)\n",
      "(1644, 14)\n",
      "(183, 14)\n",
      "Epoch 1/400\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\taki\\AppData\\Local\\Temp/ipykernel_7864/2783105689.py:142: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n",
      "  temp = np.array(temp)\n",
      "C:\\Users\\taki\\AppData\\Local\\Temp/ipykernel_7864/2783105689.py:210: UserWarning: `Model.fit_generator` is deprecated and will be removed in a future version. Please use `Model.fit`, which supports generators.\n",
      "  history = self.model.fit_generator(generator=train_gen, steps_per_epoch=train_num_batches,\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25/25 [==============================] - 6s 76ms/step - loss: 3.0216 - accuracy: 0.0477 - val_loss: 2.6236 - val_accuracy: 0.0590\n",
      "Epoch 2/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.6604 - accuracy: 0.0562 - val_loss: 2.6455 - val_accuracy: 0.0582\n",
      "Epoch 3/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.6469 - accuracy: 0.0559 - val_loss: 2.6260 - val_accuracy: 0.0574\n",
      "Epoch 4/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.6325 - accuracy: 0.0563 - val_loss: 2.6184 - val_accuracy: 0.0574\n",
      "Epoch 5/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.6204 - accuracy: 0.0564 - val_loss: 2.6177 - val_accuracy: 0.0574\n",
      "Epoch 6/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.6128 - accuracy: 0.0571 - val_loss: 2.6171 - val_accuracy: 0.0574\n",
      "Epoch 7/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.6072 - accuracy: 0.0581 - val_loss: 2.6166 - val_accuracy: 0.0594\n",
      "Epoch 8/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 2.6010 - accuracy: 0.0584 - val_loss: 2.6147 - val_accuracy: 0.0594\n",
      "Epoch 9/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.5935 - accuracy: 0.0588 - val_loss: 2.6124 - val_accuracy: 0.0594\n",
      "Epoch 10/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 2.5855 - accuracy: 0.0594 - val_loss: 2.6108 - val_accuracy: 0.0602\n",
      "Epoch 11/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.5771 - accuracy: 0.0599 - val_loss: 2.6083 - val_accuracy: 0.0602\n",
      "Epoch 12/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.5691 - accuracy: 0.0603 - val_loss: 2.6055 - val_accuracy: 0.0609\n",
      "Epoch 13/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.5617 - accuracy: 0.0610 - val_loss: 2.6027 - val_accuracy: 0.0613\n",
      "Epoch 14/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.5551 - accuracy: 0.0616 - val_loss: 2.5995 - val_accuracy: 0.0613\n",
      "Epoch 15/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 2.5488 - accuracy: 0.0621 - val_loss: 2.5971 - val_accuracy: 0.0617\n",
      "Epoch 16/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.5426 - accuracy: 0.0627 - val_loss: 2.5951 - val_accuracy: 0.0617\n",
      "Epoch 17/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 2.5365 - accuracy: 0.0631 - val_loss: 2.5927 - val_accuracy: 0.0617\n",
      "Epoch 18/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.5309 - accuracy: 0.0635 - val_loss: 2.5901 - val_accuracy: 0.0621\n",
      "Epoch 19/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 2.5257 - accuracy: 0.0638 - val_loss: 2.5877 - val_accuracy: 0.0625\n",
      "Epoch 20/400\n",
      "25/25 [==============================] - 1s 51ms/step - loss: 2.5204 - accuracy: 0.0642 - val_loss: 2.5862 - val_accuracy: 0.0629\n",
      "Epoch 21/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.5155 - accuracy: 0.0644 - val_loss: 2.5842 - val_accuracy: 0.0633\n",
      "Epoch 22/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.5155 - accuracy: 0.0645 - val_loss: 2.5906 - val_accuracy: 0.0598\n",
      "Epoch 23/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.5137 - accuracy: 0.0642 - val_loss: 2.5846 - val_accuracy: 0.0625\n",
      "Epoch 24/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 2.5056 - accuracy: 0.0650 - val_loss: 2.5823 - val_accuracy: 0.0629\n",
      "Epoch 25/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 2.4977 - accuracy: 0.0655 - val_loss: 2.5800 - val_accuracy: 0.0641\n",
      "Epoch 26/400\n",
      "25/25 [==============================] - 1s 51ms/step - loss: 2.4920 - accuracy: 0.0662 - val_loss: 2.5778 - val_accuracy: 0.0629\n",
      "Epoch 27/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 2.4862 - accuracy: 0.0668 - val_loss: 2.5756 - val_accuracy: 0.0625\n",
      "Epoch 28/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 2.4816 - accuracy: 0.0674 - val_loss: 2.5725 - val_accuracy: 0.0629\n",
      "Epoch 29/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 2.4761 - accuracy: 0.0679 - val_loss: 2.5691 - val_accuracy: 0.0637\n",
      "Epoch 30/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 2.4701 - accuracy: 0.0688 - val_loss: 2.5668 - val_accuracy: 0.0637\n",
      "Epoch 31/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.4646 - accuracy: 0.0691 - val_loss: 2.5630 - val_accuracy: 0.0656\n",
      "Epoch 32/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 2.4587 - accuracy: 0.0700 - val_loss: 2.5596 - val_accuracy: 0.0656\n",
      "Epoch 33/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.4528 - accuracy: 0.0701 - val_loss: 2.5569 - val_accuracy: 0.0656\n",
      "Epoch 34/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 2.4471 - accuracy: 0.0708 - val_loss: 2.5541 - val_accuracy: 0.0652\n",
      "Epoch 35/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.4414 - accuracy: 0.0715 - val_loss: 2.5521 - val_accuracy: 0.0645\n",
      "Epoch 36/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.4358 - accuracy: 0.0727 - val_loss: 2.5496 - val_accuracy: 0.0645\n",
      "Epoch 37/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.4304 - accuracy: 0.0735 - val_loss: 2.5498 - val_accuracy: 0.0676\n",
      "Epoch 38/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 2.4270 - accuracy: 0.0737 - val_loss: 2.5448 - val_accuracy: 0.0664\n",
      "Epoch 39/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.4187 - accuracy: 0.0748 - val_loss: 2.5422 - val_accuracy: 0.0672\n",
      "Epoch 40/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.4095 - accuracy: 0.0760 - val_loss: 2.5393 - val_accuracy: 0.0699\n",
      "Epoch 41/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 2.4028 - accuracy: 0.0769 - val_loss: 2.5332 - val_accuracy: 0.0715\n",
      "Epoch 42/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 2.3965 - accuracy: 0.0772 - val_loss: 2.5300 - val_accuracy: 0.0723\n",
      "Epoch 43/400\n",
      "25/25 [==============================] - 1s 59ms/step - loss: 2.3882 - accuracy: 0.0783 - val_loss: 2.5277 - val_accuracy: 0.0730\n",
      "Epoch 44/400\n",
      "25/25 [==============================] - 1s 56ms/step - loss: 2.3815 - accuracy: 0.0785 - val_loss: 2.5217 - val_accuracy: 0.0723\n",
      "Epoch 45/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.3807 - accuracy: 0.0787 - val_loss: 2.5247 - val_accuracy: 0.0734\n",
      "Epoch 46/400\n",
      "25/25 [==============================] - 1s 58ms/step - loss: 2.3810 - accuracy: 0.0788 - val_loss: 2.5265 - val_accuracy: 0.0719\n",
      "Epoch 47/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.3696 - accuracy: 0.0798 - val_loss: 2.5156 - val_accuracy: 0.0758\n",
      "Epoch 48/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.3563 - accuracy: 0.0819 - val_loss: 2.5111 - val_accuracy: 0.0754\n",
      "Epoch 49/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 2.3499 - accuracy: 0.0819 - val_loss: 2.5121 - val_accuracy: 0.0754\n",
      "Epoch 50/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.3425 - accuracy: 0.0828 - val_loss: 2.5089 - val_accuracy: 0.0758\n",
      "Epoch 51/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 2.3348 - accuracy: 0.0839 - val_loss: 2.5001 - val_accuracy: 0.0766\n",
      "Epoch 52/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 2.3252 - accuracy: 0.0856 - val_loss: 2.4968 - val_accuracy: 0.0785\n",
      "Epoch 53/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.3193 - accuracy: 0.0864 - val_loss: 2.4925 - val_accuracy: 0.0785\n",
      "Epoch 54/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 2.3155 - accuracy: 0.0869 - val_loss: 2.4972 - val_accuracy: 0.0762\n",
      "Epoch 55/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 2.3067 - accuracy: 0.0887 - val_loss: 2.4861 - val_accuracy: 0.0789\n",
      "Epoch 56/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 2.2967 - accuracy: 0.0902 - val_loss: 2.4821 - val_accuracy: 0.0852\n",
      "Epoch 57/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 2.2884 - accuracy: 0.0915 - val_loss: 2.4771 - val_accuracy: 0.0836\n",
      "Epoch 58/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.2810 - accuracy: 0.0931 - val_loss: 2.4786 - val_accuracy: 0.0852\n",
      "Epoch 59/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 2.2713 - accuracy: 0.0939 - val_loss: 2.4707 - val_accuracy: 0.0887\n",
      "Epoch 60/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.2616 - accuracy: 0.0950 - val_loss: 2.4683 - val_accuracy: 0.0875\n",
      "Epoch 61/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.2540 - accuracy: 0.0962 - val_loss: 2.4621 - val_accuracy: 0.0891\n",
      "Epoch 62/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.2473 - accuracy: 0.0973 - val_loss: 2.4627 - val_accuracy: 0.0875\n",
      "Epoch 63/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 2.2376 - accuracy: 0.0985 - val_loss: 2.4547 - val_accuracy: 0.0898\n",
      "Epoch 64/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.2283 - accuracy: 0.0998 - val_loss: 2.4531 - val_accuracy: 0.0918\n",
      "Epoch 65/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.2210 - accuracy: 0.1008 - val_loss: 2.4477 - val_accuracy: 0.0906\n",
      "Epoch 66/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 2.2156 - accuracy: 0.1023 - val_loss: 2.4479 - val_accuracy: 0.0891\n",
      "Epoch 67/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.2052 - accuracy: 0.1035 - val_loss: 2.4429 - val_accuracy: 0.0934\n",
      "Epoch 68/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.1959 - accuracy: 0.1047 - val_loss: 2.4406 - val_accuracy: 0.0938\n",
      "Epoch 69/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.1903 - accuracy: 0.1061 - val_loss: 2.4381 - val_accuracy: 0.0922\n",
      "Epoch 70/400\n",
      "25/25 [==============================] - 1s 51ms/step - loss: 2.1836 - accuracy: 0.1073 - val_loss: 2.4352 - val_accuracy: 0.0926\n",
      "Epoch 71/400\n",
      "25/25 [==============================] - 1s 57ms/step - loss: 2.1740 - accuracy: 0.1085 - val_loss: 2.4311 - val_accuracy: 0.0953\n",
      "Epoch 72/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 2.1670 - accuracy: 0.1095 - val_loss: 2.4265 - val_accuracy: 0.0973\n",
      "Epoch 73/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 2.1619 - accuracy: 0.1106 - val_loss: 2.4217 - val_accuracy: 0.0949\n",
      "Epoch 74/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 2.1528 - accuracy: 0.1117 - val_loss: 2.4190 - val_accuracy: 0.0949\n",
      "Epoch 75/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.1445 - accuracy: 0.1125 - val_loss: 2.4152 - val_accuracy: 0.0969\n",
      "Epoch 76/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.1396 - accuracy: 0.1131 - val_loss: 2.4092 - val_accuracy: 0.0949\n",
      "Epoch 77/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.1330 - accuracy: 0.1145 - val_loss: 2.4075 - val_accuracy: 0.0973\n",
      "Epoch 78/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.1251 - accuracy: 0.1154 - val_loss: 2.4104 - val_accuracy: 0.0992\n",
      "Epoch 79/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 2.1206 - accuracy: 0.1160 - val_loss: 2.4097 - val_accuracy: 0.0992\n",
      "Epoch 80/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 2.1144 - accuracy: 0.1171 - val_loss: 2.4124 - val_accuracy: 0.0992\n",
      "Epoch 81/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.1086 - accuracy: 0.1183 - val_loss: 2.4131 - val_accuracy: 0.1016\n",
      "Epoch 82/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 2.1112 - accuracy: 0.1177 - val_loss: 2.4045 - val_accuracy: 0.0992\n",
      "Epoch 83/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 2.1163 - accuracy: 0.1163 - val_loss: 2.3962 - val_accuracy: 0.1004\n",
      "Epoch 84/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 2.1341 - accuracy: 0.1143 - val_loss: 2.3983 - val_accuracy: 0.0977\n",
      "Epoch 85/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 2.1218 - accuracy: 0.1175 - val_loss: 2.3940 - val_accuracy: 0.0996\n",
      "Epoch 86/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 2.0865 - accuracy: 0.1241 - val_loss: 2.3855 - val_accuracy: 0.1039\n",
      "Epoch 87/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 2.0664 - accuracy: 0.1266 - val_loss: 2.3812 - val_accuracy: 0.1063\n",
      "Epoch 88/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 2.0580 - accuracy: 0.1287 - val_loss: 2.3807 - val_accuracy: 0.1047\n",
      "Epoch 89/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 2.0500 - accuracy: 0.1298 - val_loss: 2.3777 - val_accuracy: 0.1059\n",
      "Epoch 90/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 2.0421 - accuracy: 0.1310 - val_loss: 2.3763 - val_accuracy: 0.1070\n",
      "Epoch 91/400\n",
      "25/25 [==============================] - 2s 67ms/step - loss: 2.0339 - accuracy: 0.1318 - val_loss: 2.3773 - val_accuracy: 0.1070\n",
      "Epoch 92/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 2.0261 - accuracy: 0.1328 - val_loss: 2.3726 - val_accuracy: 0.1074\n",
      "Epoch 93/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.0175 - accuracy: 0.1345 - val_loss: 2.3667 - val_accuracy: 0.1078\n",
      "Epoch 94/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 2.0089 - accuracy: 0.1362 - val_loss: 2.3714 - val_accuracy: 0.1066\n",
      "Epoch 95/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 2.0011 - accuracy: 0.1376 - val_loss: 2.3694 - val_accuracy: 0.1090\n",
      "Epoch 96/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.9932 - accuracy: 0.1388 - val_loss: 2.3583 - val_accuracy: 0.1121\n",
      "Epoch 97/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.9859 - accuracy: 0.1408 - val_loss: 2.3646 - val_accuracy: 0.1094\n",
      "Epoch 98/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 1.9788 - accuracy: 0.1418 - val_loss: 2.3768 - val_accuracy: 0.1086\n",
      "Epoch 99/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 1.9747 - accuracy: 0.1408 - val_loss: 2.3526 - val_accuracy: 0.1145\n",
      "Epoch 100/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.9716 - accuracy: 0.1419 - val_loss: 2.3698 - val_accuracy: 0.1125\n",
      "Epoch 101/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.9618 - accuracy: 0.1437 - val_loss: 2.3771 - val_accuracy: 0.1090\n",
      "Epoch 102/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 1.9577 - accuracy: 0.1438 - val_loss: 2.3562 - val_accuracy: 0.1156\n",
      "Epoch 103/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.9504 - accuracy: 0.1462 - val_loss: 2.3826 - val_accuracy: 0.1109\n",
      "Epoch 104/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 1.9390 - accuracy: 0.1478 - val_loss: 2.3653 - val_accuracy: 0.1152\n",
      "Epoch 105/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 1.9347 - accuracy: 0.1488 - val_loss: 2.3610 - val_accuracy: 0.1156\n",
      "Epoch 106/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 1.9279 - accuracy: 0.1501 - val_loss: 2.3729 - val_accuracy: 0.1148\n",
      "Epoch 107/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.9181 - accuracy: 0.1514 - val_loss: 2.3553 - val_accuracy: 0.1168\n",
      "Epoch 108/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.9146 - accuracy: 0.1519 - val_loss: 2.3556 - val_accuracy: 0.1187\n",
      "Epoch 109/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.9100 - accuracy: 0.1526 - val_loss: 2.3568 - val_accuracy: 0.1180\n",
      "Epoch 110/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.9023 - accuracy: 0.1539 - val_loss: 2.3441 - val_accuracy: 0.1227\n",
      "Epoch 111/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.9006 - accuracy: 0.1531 - val_loss: 2.3370 - val_accuracy: 0.1242\n",
      "Epoch 112/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.8974 - accuracy: 0.1537 - val_loss: 2.3348 - val_accuracy: 0.1250\n",
      "Epoch 113/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.8899 - accuracy: 0.1554 - val_loss: 2.3326 - val_accuracy: 0.1254\n",
      "Epoch 114/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.8857 - accuracy: 0.1562 - val_loss: 2.3271 - val_accuracy: 0.1262\n",
      "Epoch 115/400\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25/25 [==============================] - 1s 51ms/step - loss: 1.8817 - accuracy: 0.1567 - val_loss: 2.3323 - val_accuracy: 0.1262\n",
      "Epoch 116/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.8723 - accuracy: 0.1583 - val_loss: 2.3482 - val_accuracy: 0.1234\n",
      "Epoch 117/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.8604 - accuracy: 0.1602 - val_loss: 2.3510 - val_accuracy: 0.1223\n",
      "Epoch 118/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 1.8498 - accuracy: 0.1622 - val_loss: 2.3458 - val_accuracy: 0.1246\n",
      "Epoch 119/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.8403 - accuracy: 0.1635 - val_loss: 2.3370 - val_accuracy: 0.1246\n",
      "Epoch 120/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 1.8315 - accuracy: 0.1649 - val_loss: 2.3330 - val_accuracy: 0.1270\n",
      "Epoch 121/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.8244 - accuracy: 0.1662 - val_loss: 2.3271 - val_accuracy: 0.1289\n",
      "Epoch 122/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.8181 - accuracy: 0.1667 - val_loss: 2.3242 - val_accuracy: 0.1305\n",
      "Epoch 123/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.8105 - accuracy: 0.1679 - val_loss: 2.3222 - val_accuracy: 0.1305\n",
      "Epoch 124/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.8037 - accuracy: 0.1688 - val_loss: 2.3222 - val_accuracy: 0.1324\n",
      "Epoch 125/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.8014 - accuracy: 0.1693 - val_loss: 2.3213 - val_accuracy: 0.1316\n",
      "Epoch 126/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 1.7984 - accuracy: 0.1698 - val_loss: 2.3218 - val_accuracy: 0.1312\n",
      "Epoch 127/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 1.7894 - accuracy: 0.1713 - val_loss: 2.3241 - val_accuracy: 0.1312\n",
      "Epoch 128/400\n",
      "25/25 [==============================] - 1s 52ms/step - loss: 1.7874 - accuracy: 0.1712 - val_loss: 2.3312 - val_accuracy: 0.1297\n",
      "Epoch 129/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.7850 - accuracy: 0.1714 - val_loss: 2.3255 - val_accuracy: 0.1312\n",
      "Epoch 130/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 1.7737 - accuracy: 0.1736 - val_loss: 2.3305 - val_accuracy: 0.1297\n",
      "Epoch 131/400\n",
      "25/25 [==============================] - 1s 55ms/step - loss: 1.7679 - accuracy: 0.1738 - val_loss: 2.3432 - val_accuracy: 0.1285\n",
      "Epoch 132/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 1.7644 - accuracy: 0.1747 - val_loss: 2.3301 - val_accuracy: 0.1324\n",
      "Epoch 133/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.7562 - accuracy: 0.1764 - val_loss: 2.3383 - val_accuracy: 0.1328\n",
      "Epoch 134/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.7493 - accuracy: 0.1781 - val_loss: 2.3498 - val_accuracy: 0.1289\n",
      "Epoch 135/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.7465 - accuracy: 0.1781 - val_loss: 2.3327 - val_accuracy: 0.1336\n",
      "Epoch 136/400\n",
      "25/25 [==============================] - 1s 55ms/step - loss: 1.7423 - accuracy: 0.1787 - val_loss: 2.3403 - val_accuracy: 0.1320\n",
      "Epoch 137/400\n",
      "25/25 [==============================] - 2s 62ms/step - loss: 1.7351 - accuracy: 0.1805 - val_loss: 2.3549 - val_accuracy: 0.1270\n",
      "Epoch 138/400\n",
      "25/25 [==============================] - 1s 54ms/step - loss: 1.7338 - accuracy: 0.1803 - val_loss: 2.3274 - val_accuracy: 0.1352\n",
      "Epoch 139/400\n",
      "25/25 [==============================] - 1s 55ms/step - loss: 1.7333 - accuracy: 0.1810 - val_loss: 2.3454 - val_accuracy: 0.1316\n",
      "Epoch 140/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.7266 - accuracy: 0.1818 - val_loss: 2.3527 - val_accuracy: 0.1273\n",
      "Epoch 141/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.7291 - accuracy: 0.1808 - val_loss: 2.3342 - val_accuracy: 0.1340\n",
      "Epoch 142/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 1.7385 - accuracy: 0.1783 - val_loss: 2.3357 - val_accuracy: 0.1320\n",
      "Epoch 143/400\n",
      "25/25 [==============================] - 1s 51ms/step - loss: 1.7380 - accuracy: 0.1760 - val_loss: 2.3263 - val_accuracy: 0.1371\n",
      "Epoch 144/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 1.7267 - accuracy: 0.1782 - val_loss: 2.3082 - val_accuracy: 0.1367\n",
      "Epoch 145/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.7191 - accuracy: 0.1799 - val_loss: 2.3006 - val_accuracy: 0.1387\n",
      "Epoch 146/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.7142 - accuracy: 0.1808 - val_loss: 2.3009 - val_accuracy: 0.1406\n",
      "Epoch 147/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.7055 - accuracy: 0.1830 - val_loss: 2.3410 - val_accuracy: 0.1371\n",
      "Epoch 148/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.6937 - accuracy: 0.1867 - val_loss: 2.3475 - val_accuracy: 0.1332\n",
      "Epoch 149/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.6857 - accuracy: 0.1872 - val_loss: 2.3115 - val_accuracy: 0.1422\n",
      "Epoch 150/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.6778 - accuracy: 0.1874 - val_loss: 2.2966 - val_accuracy: 0.1398\n",
      "Epoch 151/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.6695 - accuracy: 0.1882 - val_loss: 2.2970 - val_accuracy: 0.1437\n",
      "Epoch 152/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.6604 - accuracy: 0.1902 - val_loss: 2.3314 - val_accuracy: 0.1379\n",
      "Epoch 153/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.6458 - accuracy: 0.1936 - val_loss: 2.3337 - val_accuracy: 0.1371\n",
      "Epoch 154/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.6365 - accuracy: 0.1953 - val_loss: 2.3114 - val_accuracy: 0.1441\n",
      "Epoch 155/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.6287 - accuracy: 0.1973 - val_loss: 2.2986 - val_accuracy: 0.1484\n",
      "Epoch 156/400\n",
      "25/25 [==============================] - 1s 49ms/step - loss: 1.6213 - accuracy: 0.1982 - val_loss: 2.2967 - val_accuracy: 0.1461\n",
      "Epoch 157/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.6142 - accuracy: 0.1986 - val_loss: 2.3029 - val_accuracy: 0.1453\n",
      "Epoch 158/400\n",
      "25/25 [==============================] - 1s 50ms/step - loss: 1.6063 - accuracy: 0.1994 - val_loss: 2.3120 - val_accuracy: 0.1445\n",
      "Epoch 159/400\n",
      "25/25 [==============================] - 1s 55ms/step - loss: 1.5984 - accuracy: 0.2008 - val_loss: 2.3188 - val_accuracy: 0.1453\n",
      "Epoch 160/400\n",
      "25/25 [==============================] - 1s 51ms/step - loss: 1.5912 - accuracy: 0.2023 - val_loss: 2.3209 - val_accuracy: 0.1445\n",
      "Epoch 161/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.5842 - accuracy: 0.2034 - val_loss: 2.3192 - val_accuracy: 0.1449\n",
      "Epoch 162/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.5776 - accuracy: 0.2046 - val_loss: 2.3162 - val_accuracy: 0.1461\n",
      "Epoch 163/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.5709 - accuracy: 0.2055 - val_loss: 2.3121 - val_accuracy: 0.1473\n",
      "Epoch 164/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.5642 - accuracy: 0.2063 - val_loss: 2.3079 - val_accuracy: 0.1484\n",
      "Epoch 165/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.5574 - accuracy: 0.2068 - val_loss: 2.3040 - val_accuracy: 0.1484\n",
      "Epoch 166/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.5509 - accuracy: 0.2077 - val_loss: 2.3022 - val_accuracy: 0.1500\n",
      "Epoch 167/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.5442 - accuracy: 0.2084 - val_loss: 2.3015 - val_accuracy: 0.1500\n",
      "Epoch 168/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.5374 - accuracy: 0.2094 - val_loss: 2.3007 - val_accuracy: 0.1500\n",
      "Epoch 169/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.5303 - accuracy: 0.2102 - val_loss: 2.2962 - val_accuracy: 0.1531\n",
      "Epoch 170/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.5242 - accuracy: 0.2107 - val_loss: 2.2912 - val_accuracy: 0.1527\n",
      "Epoch 171/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.5218 - accuracy: 0.2112 - val_loss: 2.2909 - val_accuracy: 0.1508\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 172/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.5300 - accuracy: 0.2081 - val_loss: 2.3230 - val_accuracy: 0.1465\n",
      "Epoch 173/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.5543 - accuracy: 0.2031 - val_loss: 2.3071 - val_accuracy: 0.1453\n",
      "Epoch 174/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.5377 - accuracy: 0.2055 - val_loss: 2.2796 - val_accuracy: 0.1437\n",
      "Epoch 175/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.5269 - accuracy: 0.2071 - val_loss: 2.3156 - val_accuracy: 0.1504\n",
      "Epoch 176/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.5116 - accuracy: 0.2099 - val_loss: 2.2928 - val_accuracy: 0.1484\n",
      "Epoch 177/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4965 - accuracy: 0.2139 - val_loss: 2.2817 - val_accuracy: 0.1512\n",
      "Epoch 178/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4905 - accuracy: 0.2142 - val_loss: 2.2994 - val_accuracy: 0.1523\n",
      "Epoch 179/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4862 - accuracy: 0.2138 - val_loss: 2.3028 - val_accuracy: 0.1535\n",
      "Epoch 180/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4814 - accuracy: 0.2146 - val_loss: 2.2838 - val_accuracy: 0.1539\n",
      "Epoch 181/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4785 - accuracy: 0.2144 - val_loss: 2.2913 - val_accuracy: 0.1555\n",
      "Epoch 182/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4766 - accuracy: 0.2152 - val_loss: 2.3328 - val_accuracy: 0.1512\n",
      "Epoch 183/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.4762 - accuracy: 0.2152 - val_loss: 2.3026 - val_accuracy: 0.1531\n",
      "Epoch 184/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.4738 - accuracy: 0.2145 - val_loss: 2.3123 - val_accuracy: 0.1551\n",
      "Epoch 185/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.4625 - accuracy: 0.2170 - val_loss: 2.3844 - val_accuracy: 0.1437\n",
      "Epoch 186/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.4601 - accuracy: 0.2170 - val_loss: 2.3576 - val_accuracy: 0.1492\n",
      "Epoch 187/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.4605 - accuracy: 0.2166 - val_loss: 2.3746 - val_accuracy: 0.1469\n",
      "Epoch 188/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.4559 - accuracy: 0.2169 - val_loss: 2.3914 - val_accuracy: 0.1457\n",
      "Epoch 189/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.4516 - accuracy: 0.2170 - val_loss: 2.3324 - val_accuracy: 0.1504\n",
      "Epoch 190/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.4583 - accuracy: 0.2152 - val_loss: 2.3026 - val_accuracy: 0.1523\n",
      "Epoch 191/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4635 - accuracy: 0.2148 - val_loss: 2.3040 - val_accuracy: 0.1488\n",
      "Epoch 192/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4681 - accuracy: 0.2146 - val_loss: 2.3248 - val_accuracy: 0.1461\n",
      "Epoch 193/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.4556 - accuracy: 0.2156 - val_loss: 2.3706 - val_accuracy: 0.1492\n",
      "Epoch 194/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.4311 - accuracy: 0.2214 - val_loss: 2.3512 - val_accuracy: 0.1535\n",
      "Epoch 195/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.4118 - accuracy: 0.2243 - val_loss: 2.3233 - val_accuracy: 0.1559\n",
      "Epoch 196/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3996 - accuracy: 0.2267 - val_loss: 2.3149 - val_accuracy: 0.1562\n",
      "Epoch 197/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3910 - accuracy: 0.2281 - val_loss: 2.3182 - val_accuracy: 0.1555\n",
      "Epoch 198/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3848 - accuracy: 0.2294 - val_loss: 2.3257 - val_accuracy: 0.1562\n",
      "Epoch 199/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3796 - accuracy: 0.2303 - val_loss: 2.3354 - val_accuracy: 0.1570\n",
      "Epoch 200/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3749 - accuracy: 0.2313 - val_loss: 2.3423 - val_accuracy: 0.1582\n",
      "Epoch 201/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3697 - accuracy: 0.2325 - val_loss: 2.3417 - val_accuracy: 0.1582\n",
      "Epoch 202/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3650 - accuracy: 0.2327 - val_loss: 2.3409 - val_accuracy: 0.1590\n",
      "Epoch 203/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3619 - accuracy: 0.2332 - val_loss: 2.3491 - val_accuracy: 0.1590\n",
      "Epoch 204/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3601 - accuracy: 0.2333 - val_loss: 2.3539 - val_accuracy: 0.1578\n",
      "Epoch 205/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3589 - accuracy: 0.2334 - val_loss: 2.3295 - val_accuracy: 0.1590\n",
      "Epoch 206/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3641 - accuracy: 0.2325 - val_loss: 2.3206 - val_accuracy: 0.1605\n",
      "Epoch 207/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3770 - accuracy: 0.2308 - val_loss: 2.3894 - val_accuracy: 0.1539\n",
      "Epoch 208/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3858 - accuracy: 0.2285 - val_loss: 2.3371 - val_accuracy: 0.1578\n",
      "Epoch 209/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3695 - accuracy: 0.2317 - val_loss: 2.3653 - val_accuracy: 0.1605\n",
      "Epoch 210/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3641 - accuracy: 0.2328 - val_loss: 2.4531 - val_accuracy: 0.1477\n",
      "Epoch 211/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3975 - accuracy: 0.2256 - val_loss: 2.4747 - val_accuracy: 0.1484\n",
      "Epoch 212/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.4166 - accuracy: 0.2232 - val_loss: 2.4905 - val_accuracy: 0.1484\n",
      "Epoch 213/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.4316 - accuracy: 0.2204 - val_loss: 2.4024 - val_accuracy: 0.1559\n",
      "Epoch 214/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.4055 - accuracy: 0.2249 - val_loss: 2.3388 - val_accuracy: 0.1566\n",
      "Epoch 215/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3714 - accuracy: 0.2317 - val_loss: 2.3386 - val_accuracy: 0.1594\n",
      "Epoch 216/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3504 - accuracy: 0.2358 - val_loss: 2.3891 - val_accuracy: 0.1582\n",
      "Epoch 217/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3320 - accuracy: 0.2373 - val_loss: 2.4227 - val_accuracy: 0.1539\n",
      "Epoch 218/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3209 - accuracy: 0.2396 - val_loss: 2.4179 - val_accuracy: 0.1523\n",
      "Epoch 219/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.3135 - accuracy: 0.2411 - val_loss: 2.3909 - val_accuracy: 0.1559\n",
      "Epoch 220/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3078 - accuracy: 0.2422 - val_loss: 2.3702 - val_accuracy: 0.1590\n",
      "Epoch 221/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.3025 - accuracy: 0.2438 - val_loss: 2.3617 - val_accuracy: 0.1605\n",
      "Epoch 222/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.2999 - accuracy: 0.2444 - val_loss: 2.3684 - val_accuracy: 0.1594\n",
      "Epoch 223/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2954 - accuracy: 0.2452 - val_loss: 2.3823 - val_accuracy: 0.1582\n",
      "Epoch 224/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2918 - accuracy: 0.2449 - val_loss: 2.3888 - val_accuracy: 0.1582\n",
      "Epoch 225/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2927 - accuracy: 0.2445 - val_loss: 2.3890 - val_accuracy: 0.1582\n",
      "Epoch 226/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2952 - accuracy: 0.2443 - val_loss: 2.3897 - val_accuracy: 0.1590\n",
      "Epoch 227/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2977 - accuracy: 0.2445 - val_loss: 2.4293 - val_accuracy: 0.1547\n",
      "Epoch 228/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3058 - accuracy: 0.2428 - val_loss: 2.4802 - val_accuracy: 0.1527\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 229/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3058 - accuracy: 0.2419 - val_loss: 2.5075 - val_accuracy: 0.1520\n",
      "Epoch 230/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3103 - accuracy: 0.2409 - val_loss: 2.4672 - val_accuracy: 0.1551\n",
      "Epoch 231/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.3060 - accuracy: 0.2421 - val_loss: 2.3778 - val_accuracy: 0.1586\n",
      "Epoch 232/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2916 - accuracy: 0.2437 - val_loss: 2.3525 - val_accuracy: 0.1582\n",
      "Epoch 233/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.2959 - accuracy: 0.2439 - val_loss: 2.3941 - val_accuracy: 0.1609\n",
      "Epoch 234/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.2817 - accuracy: 0.2460 - val_loss: 2.4820 - val_accuracy: 0.1559\n",
      "Epoch 235/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2733 - accuracy: 0.2475 - val_loss: 2.4613 - val_accuracy: 0.1531\n",
      "Epoch 236/400\n",
      "25/25 [==============================] - 1s 57ms/step - loss: 1.2643 - accuracy: 0.2488 - val_loss: 2.4046 - val_accuracy: 0.1590\n",
      "Epoch 237/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2543 - accuracy: 0.2512 - val_loss: 2.3870 - val_accuracy: 0.1598\n",
      "Epoch 238/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2464 - accuracy: 0.2525 - val_loss: 2.4112 - val_accuracy: 0.1586\n",
      "Epoch 239/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2379 - accuracy: 0.2538 - val_loss: 2.4257 - val_accuracy: 0.1590\n",
      "Epoch 240/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2329 - accuracy: 0.2546 - val_loss: 2.4253 - val_accuracy: 0.1598\n",
      "Epoch 241/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2278 - accuracy: 0.2555 - val_loss: 2.4260 - val_accuracy: 0.1590\n",
      "Epoch 242/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2243 - accuracy: 0.2560 - val_loss: 2.4311 - val_accuracy: 0.1598\n",
      "Epoch 243/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.2216 - accuracy: 0.2565 - val_loss: 2.4436 - val_accuracy: 0.1590\n",
      "Epoch 244/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2194 - accuracy: 0.2568 - val_loss: 2.4616 - val_accuracy: 0.1574\n",
      "Epoch 245/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.2179 - accuracy: 0.2570 - val_loss: 2.4827 - val_accuracy: 0.1562\n",
      "Epoch 246/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2183 - accuracy: 0.2572 - val_loss: 2.5009 - val_accuracy: 0.1539\n",
      "Epoch 247/400\n",
      "25/25 [==============================] - 2s 63ms/step - loss: 1.2212 - accuracy: 0.2559 - val_loss: 2.5000 - val_accuracy: 0.1562\n",
      "Epoch 248/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2264 - accuracy: 0.2552 - val_loss: 2.4945 - val_accuracy: 0.1574\n",
      "Epoch 249/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2304 - accuracy: 0.2547 - val_loss: 2.4899 - val_accuracy: 0.1586\n",
      "Epoch 250/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2292 - accuracy: 0.2547 - val_loss: 2.4427 - val_accuracy: 0.1602\n",
      "Epoch 251/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2244 - accuracy: 0.2552 - val_loss: 2.3942 - val_accuracy: 0.1609\n",
      "Epoch 252/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2269 - accuracy: 0.2543 - val_loss: 2.4010 - val_accuracy: 0.1594\n",
      "Epoch 253/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.2347 - accuracy: 0.2537 - val_loss: 2.4730 - val_accuracy: 0.1578\n",
      "Epoch 254/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2407 - accuracy: 0.2508 - val_loss: 2.5791 - val_accuracy: 0.1496\n",
      "Epoch 255/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.2412 - accuracy: 0.2507 - val_loss: 2.5275 - val_accuracy: 0.1527\n",
      "Epoch 256/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2239 - accuracy: 0.2540 - val_loss: 2.4371 - val_accuracy: 0.1605\n",
      "Epoch 257/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2076 - accuracy: 0.2573 - val_loss: 2.4272 - val_accuracy: 0.1629\n",
      "Epoch 258/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1947 - accuracy: 0.2598 - val_loss: 2.4724 - val_accuracy: 0.1582\n",
      "Epoch 259/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1806 - accuracy: 0.2608 - val_loss: 2.4930 - val_accuracy: 0.1594\n",
      "Epoch 260/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.1702 - accuracy: 0.2631 - val_loss: 2.4932 - val_accuracy: 0.1590\n",
      "Epoch 261/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1637 - accuracy: 0.2645 - val_loss: 2.4874 - val_accuracy: 0.1598\n",
      "Epoch 262/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1591 - accuracy: 0.2655 - val_loss: 2.4860 - val_accuracy: 0.1602\n",
      "Epoch 263/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1552 - accuracy: 0.2659 - val_loss: 2.4884 - val_accuracy: 0.1605\n",
      "Epoch 264/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.1517 - accuracy: 0.2666 - val_loss: 2.4953 - val_accuracy: 0.1605\n",
      "Epoch 265/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1490 - accuracy: 0.2670 - val_loss: 2.5008 - val_accuracy: 0.1598\n",
      "Epoch 266/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1472 - accuracy: 0.2677 - val_loss: 2.5110 - val_accuracy: 0.1605\n",
      "Epoch 267/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1454 - accuracy: 0.2685 - val_loss: 2.5122 - val_accuracy: 0.1605\n",
      "Epoch 268/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.1437 - accuracy: 0.2687 - val_loss: 2.5163 - val_accuracy: 0.1605\n",
      "Epoch 269/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1424 - accuracy: 0.2690 - val_loss: 2.5188 - val_accuracy: 0.1598\n",
      "Epoch 270/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1423 - accuracy: 0.2690 - val_loss: 2.5166 - val_accuracy: 0.1605\n",
      "Epoch 271/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1436 - accuracy: 0.2687 - val_loss: 2.5195 - val_accuracy: 0.1605\n",
      "Epoch 272/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1465 - accuracy: 0.2682 - val_loss: 2.5267 - val_accuracy: 0.1574\n",
      "Epoch 273/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1496 - accuracy: 0.2667 - val_loss: 2.5135 - val_accuracy: 0.1586\n",
      "Epoch 274/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1543 - accuracy: 0.2650 - val_loss: 2.4675 - val_accuracy: 0.1617\n",
      "Epoch 275/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1656 - accuracy: 0.2624 - val_loss: 2.4309 - val_accuracy: 0.1633\n",
      "Epoch 276/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1885 - accuracy: 0.2592 - val_loss: 2.4604 - val_accuracy: 0.1645\n",
      "Epoch 277/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.2063 - accuracy: 0.2556 - val_loss: 2.5585 - val_accuracy: 0.1562\n",
      "Epoch 278/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.2160 - accuracy: 0.2521 - val_loss: 2.6858 - val_accuracy: 0.1516\n",
      "Epoch 279/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.1989 - accuracy: 0.2554 - val_loss: 2.5600 - val_accuracy: 0.1609\n",
      "Epoch 280/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1666 - accuracy: 0.2632 - val_loss: 2.4784 - val_accuracy: 0.1656\n",
      "Epoch 281/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1394 - accuracy: 0.2673 - val_loss: 2.4895 - val_accuracy: 0.1652\n",
      "Epoch 282/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1259 - accuracy: 0.2697 - val_loss: 2.5220 - val_accuracy: 0.1613\n",
      "Epoch 283/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1199 - accuracy: 0.2710 - val_loss: 2.5590 - val_accuracy: 0.1605\n",
      "Epoch 284/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1144 - accuracy: 0.2715 - val_loss: 2.5906 - val_accuracy: 0.1578\n",
      "Epoch 285/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1109 - accuracy: 0.2723 - val_loss: 2.5769 - val_accuracy: 0.1605\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 286/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1073 - accuracy: 0.2738 - val_loss: 2.5391 - val_accuracy: 0.1625\n",
      "Epoch 287/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.1037 - accuracy: 0.2746 - val_loss: 2.5152 - val_accuracy: 0.1617\n",
      "Epoch 288/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 1.0993 - accuracy: 0.2746 - val_loss: 2.5095 - val_accuracy: 0.1633\n",
      "Epoch 289/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.0988 - accuracy: 0.2752 - val_loss: 2.5204 - val_accuracy: 0.1645\n",
      "Epoch 290/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.1005 - accuracy: 0.2742 - val_loss: 2.5523 - val_accuracy: 0.1641\n",
      "Epoch 291/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.1016 - accuracy: 0.2742 - val_loss: 2.6074 - val_accuracy: 0.1602\n",
      "Epoch 292/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.1041 - accuracy: 0.2729 - val_loss: 2.6355 - val_accuracy: 0.1582\n",
      "Epoch 293/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.1024 - accuracy: 0.2739 - val_loss: 2.6171 - val_accuracy: 0.1590\n",
      "Epoch 294/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0984 - accuracy: 0.2743 - val_loss: 2.5719 - val_accuracy: 0.1625\n",
      "Epoch 295/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0942 - accuracy: 0.2761 - val_loss: 2.5327 - val_accuracy: 0.1641\n",
      "Epoch 296/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0898 - accuracy: 0.2765 - val_loss: 2.5214 - val_accuracy: 0.1664\n",
      "Epoch 297/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0872 - accuracy: 0.2761 - val_loss: 2.5299 - val_accuracy: 0.1652\n",
      "Epoch 298/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0864 - accuracy: 0.2760 - val_loss: 2.5546 - val_accuracy: 0.1602\n",
      "Epoch 299/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0899 - accuracy: 0.2762 - val_loss: 2.5728 - val_accuracy: 0.1605\n",
      "Epoch 300/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0965 - accuracy: 0.2746 - val_loss: 2.6177 - val_accuracy: 0.1617\n",
      "Epoch 301/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0988 - accuracy: 0.2729 - val_loss: 2.6788 - val_accuracy: 0.1574\n",
      "Epoch 302/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1061 - accuracy: 0.2718 - val_loss: 2.6878 - val_accuracy: 0.1570\n",
      "Epoch 303/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.1044 - accuracy: 0.2723 - val_loss: 2.6053 - val_accuracy: 0.1641\n",
      "Epoch 304/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0974 - accuracy: 0.2742 - val_loss: 2.5169 - val_accuracy: 0.1688\n",
      "Epoch 305/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0905 - accuracy: 0.2754 - val_loss: 2.5299 - val_accuracy: 0.1660\n",
      "Epoch 306/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0870 - accuracy: 0.2753 - val_loss: 2.5826 - val_accuracy: 0.1637\n",
      "Epoch 307/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0811 - accuracy: 0.2771 - val_loss: 2.6324 - val_accuracy: 0.1605\n",
      "Epoch 308/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0743 - accuracy: 0.2781 - val_loss: 2.6544 - val_accuracy: 0.1590\n",
      "Epoch 309/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0684 - accuracy: 0.2796 - val_loss: 2.6259 - val_accuracy: 0.1613\n",
      "Epoch 310/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0616 - accuracy: 0.2808 - val_loss: 2.5746 - val_accuracy: 0.1652\n",
      "Epoch 311/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0557 - accuracy: 0.2817 - val_loss: 2.5601 - val_accuracy: 0.1637\n",
      "Epoch 312/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0511 - accuracy: 0.2825 - val_loss: 2.5740 - val_accuracy: 0.1652\n",
      "Epoch 313/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0499 - accuracy: 0.2829 - val_loss: 2.5922 - val_accuracy: 0.1664\n",
      "Epoch 314/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0490 - accuracy: 0.2827 - val_loss: 2.6260 - val_accuracy: 0.1637\n",
      "Epoch 315/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 1.0481 - accuracy: 0.2823 - val_loss: 2.6564 - val_accuracy: 0.1609\n",
      "Epoch 316/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0485 - accuracy: 0.2817 - val_loss: 2.6664 - val_accuracy: 0.1621\n",
      "Epoch 317/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0486 - accuracy: 0.2822 - val_loss: 2.6542 - val_accuracy: 0.1613\n",
      "Epoch 318/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0512 - accuracy: 0.2824 - val_loss: 2.6175 - val_accuracy: 0.1660\n",
      "Epoch 319/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0516 - accuracy: 0.2835 - val_loss: 2.5892 - val_accuracy: 0.1645\n",
      "Epoch 320/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0457 - accuracy: 0.2829 - val_loss: 2.5565 - val_accuracy: 0.1641\n",
      "Epoch 321/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0439 - accuracy: 0.2833 - val_loss: 2.5529 - val_accuracy: 0.1660\n",
      "Epoch 322/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0498 - accuracy: 0.2823 - val_loss: 2.6008 - val_accuracy: 0.1680\n",
      "Epoch 323/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0554 - accuracy: 0.2817 - val_loss: 2.6782 - val_accuracy: 0.1609\n",
      "Epoch 324/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.0561 - accuracy: 0.2811 - val_loss: 2.7440 - val_accuracy: 0.1594\n",
      "Epoch 325/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0541 - accuracy: 0.2804 - val_loss: 2.7035 - val_accuracy: 0.1609\n",
      "Epoch 326/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 1.0444 - accuracy: 0.2833 - val_loss: 2.6257 - val_accuracy: 0.1645\n",
      "Epoch 327/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.0360 - accuracy: 0.2844 - val_loss: 2.6107 - val_accuracy: 0.1656\n",
      "Epoch 328/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.0289 - accuracy: 0.2859 - val_loss: 2.6292 - val_accuracy: 0.1656\n",
      "Epoch 329/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0233 - accuracy: 0.2867 - val_loss: 2.6539 - val_accuracy: 0.1648\n",
      "Epoch 330/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0206 - accuracy: 0.2873 - val_loss: 2.6749 - val_accuracy: 0.1648\n",
      "Epoch 331/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 1.0170 - accuracy: 0.2879 - val_loss: 2.6737 - val_accuracy: 0.1637\n",
      "Epoch 332/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0142 - accuracy: 0.2883 - val_loss: 2.6544 - val_accuracy: 0.1641\n",
      "Epoch 333/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0117 - accuracy: 0.2889 - val_loss: 2.6509 - val_accuracy: 0.1633\n",
      "Epoch 334/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0089 - accuracy: 0.2895 - val_loss: 2.6464 - val_accuracy: 0.1645\n",
      "Epoch 335/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0074 - accuracy: 0.2897 - val_loss: 2.6595 - val_accuracy: 0.1645\n",
      "Epoch 336/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0062 - accuracy: 0.2903 - val_loss: 2.6748 - val_accuracy: 0.1652\n",
      "Epoch 337/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0050 - accuracy: 0.2905 - val_loss: 2.6847 - val_accuracy: 0.1637\n",
      "Epoch 338/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0039 - accuracy: 0.2901 - val_loss: 2.6857 - val_accuracy: 0.1633\n",
      "Epoch 339/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0051 - accuracy: 0.2899 - val_loss: 2.6987 - val_accuracy: 0.1629\n",
      "Epoch 340/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0048 - accuracy: 0.2899 - val_loss: 2.7049 - val_accuracy: 0.1602\n",
      "Epoch 341/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0007 - accuracy: 0.2907 - val_loss: 2.6758 - val_accuracy: 0.1617\n",
      "Epoch 342/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0021 - accuracy: 0.2903 - val_loss: 2.6796 - val_accuracy: 0.1641\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 343/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0078 - accuracy: 0.2892 - val_loss: 2.6959 - val_accuracy: 0.1652\n",
      "Epoch 344/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0054 - accuracy: 0.2902 - val_loss: 2.6509 - val_accuracy: 0.1656\n",
      "Epoch 345/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 1.0036 - accuracy: 0.2904 - val_loss: 2.6273 - val_accuracy: 0.1656\n",
      "Epoch 346/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0185 - accuracy: 0.2868 - val_loss: 2.6966 - val_accuracy: 0.1664\n",
      "Epoch 347/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 1.0208 - accuracy: 0.2863 - val_loss: 2.6650 - val_accuracy: 0.1672\n",
      "Epoch 348/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 1.0149 - accuracy: 0.2876 - val_loss: 2.6346 - val_accuracy: 0.1680\n",
      "Epoch 349/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.0238 - accuracy: 0.2842 - val_loss: 2.7408 - val_accuracy: 0.1641\n",
      "Epoch 350/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.0271 - accuracy: 0.2848 - val_loss: 2.7759 - val_accuracy: 0.1645\n",
      "Epoch 351/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 1.0281 - accuracy: 0.2835 - val_loss: 2.8344 - val_accuracy: 0.1617\n",
      "Epoch 352/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.0470 - accuracy: 0.2791 - val_loss: 2.9243 - val_accuracy: 0.1617\n",
      "Epoch 353/400\n",
      "25/25 [==============================] - 1s 48ms/step - loss: 1.0848 - accuracy: 0.2725 - val_loss: 2.9107 - val_accuracy: 0.1617\n",
      "Epoch 354/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.0947 - accuracy: 0.2725 - val_loss: 2.7317 - val_accuracy: 0.1664\n",
      "Epoch 355/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.0682 - accuracy: 0.2774 - val_loss: 2.6988 - val_accuracy: 0.1645\n",
      "Epoch 356/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 1.0310 - accuracy: 0.2830 - val_loss: 2.6719 - val_accuracy: 0.1637\n",
      "Epoch 357/400\n",
      "25/25 [==============================] - 1s 46ms/step - loss: 1.0093 - accuracy: 0.2875 - val_loss: 2.7165 - val_accuracy: 0.1668\n",
      "Epoch 358/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 0.9941 - accuracy: 0.2892 - val_loss: 2.7806 - val_accuracy: 0.1629\n",
      "Epoch 359/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9841 - accuracy: 0.2917 - val_loss: 2.8346 - val_accuracy: 0.1641\n",
      "Epoch 360/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9844 - accuracy: 0.2924 - val_loss: 2.8445 - val_accuracy: 0.1617\n",
      "Epoch 361/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 0.9843 - accuracy: 0.2934 - val_loss: 2.7846 - val_accuracy: 0.1656\n",
      "Epoch 362/400\n",
      "25/25 [==============================] - 1s 47ms/step - loss: 0.9783 - accuracy: 0.2943 - val_loss: 2.7237 - val_accuracy: 0.1652\n",
      "Epoch 363/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9748 - accuracy: 0.2945 - val_loss: 2.7152 - val_accuracy: 0.1656\n",
      "Epoch 364/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9747 - accuracy: 0.2943 - val_loss: 2.7382 - val_accuracy: 0.1656\n",
      "Epoch 365/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9737 - accuracy: 0.2946 - val_loss: 2.8006 - val_accuracy: 0.1625\n",
      "Epoch 366/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9744 - accuracy: 0.2948 - val_loss: 2.8567 - val_accuracy: 0.1641\n",
      "Epoch 367/400\n",
      "25/25 [==============================] - 1s 42ms/step - loss: 0.9732 - accuracy: 0.2946 - val_loss: 2.8601 - val_accuracy: 0.1652\n",
      "Epoch 368/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 0.9708 - accuracy: 0.2949 - val_loss: 2.8170 - val_accuracy: 0.1652\n",
      "Epoch 369/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9666 - accuracy: 0.2966 - val_loss: 2.7800 - val_accuracy: 0.1656\n",
      "Epoch 370/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 0.9627 - accuracy: 0.2977 - val_loss: 2.7673 - val_accuracy: 0.1676\n",
      "Epoch 371/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9600 - accuracy: 0.2970 - val_loss: 2.7760 - val_accuracy: 0.1668\n",
      "Epoch 372/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9581 - accuracy: 0.2975 - val_loss: 2.8038 - val_accuracy: 0.1652\n",
      "Epoch 373/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9557 - accuracy: 0.2981 - val_loss: 2.8169 - val_accuracy: 0.1637\n",
      "Epoch 374/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9538 - accuracy: 0.2983 - val_loss: 2.8110 - val_accuracy: 0.1637\n",
      "Epoch 375/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9522 - accuracy: 0.2989 - val_loss: 2.8083 - val_accuracy: 0.1656\n",
      "Epoch 376/400\n",
      "25/25 [==============================] - 1s 53ms/step - loss: 0.9537 - accuracy: 0.2991 - val_loss: 2.8108 - val_accuracy: 0.1648\n",
      "Epoch 377/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9552 - accuracy: 0.2986 - val_loss: 2.8321 - val_accuracy: 0.1676\n",
      "Epoch 378/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9588 - accuracy: 0.2975 - val_loss: 2.8953 - val_accuracy: 0.1664\n",
      "Epoch 379/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9658 - accuracy: 0.2957 - val_loss: 2.9450 - val_accuracy: 0.1645\n",
      "Epoch 380/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9753 - accuracy: 0.2942 - val_loss: 3.0047 - val_accuracy: 0.1633\n",
      "Epoch 381/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 0.9855 - accuracy: 0.2914 - val_loss: 3.0430 - val_accuracy: 0.1621\n",
      "Epoch 382/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9942 - accuracy: 0.2907 - val_loss: 2.9863 - val_accuracy: 0.1609\n",
      "Epoch 383/400\n",
      "25/25 [==============================] - 1s 45ms/step - loss: 0.9905 - accuracy: 0.2912 - val_loss: 2.8479 - val_accuracy: 0.1660\n",
      "Epoch 384/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9838 - accuracy: 0.2930 - val_loss: 2.7592 - val_accuracy: 0.1695\n",
      "Epoch 385/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9767 - accuracy: 0.2934 - val_loss: 2.7416 - val_accuracy: 0.1676\n",
      "Epoch 386/400\n",
      "25/25 [==============================] - 1s 44ms/step - loss: 0.9690 - accuracy: 0.2955 - val_loss: 2.7908 - val_accuracy: 0.1688\n",
      "Epoch 387/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9690 - accuracy: 0.2958 - val_loss: 2.8886 - val_accuracy: 0.1699\n",
      "Epoch 388/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9712 - accuracy: 0.2942 - val_loss: 2.9559 - val_accuracy: 0.1680\n",
      "Epoch 389/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9671 - accuracy: 0.2954 - val_loss: 2.9213 - val_accuracy: 0.1695\n",
      "Epoch 390/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9584 - accuracy: 0.2981 - val_loss: 2.8365 - val_accuracy: 0.1672\n",
      "Epoch 391/400\n",
      "25/25 [==============================] - 1s 41ms/step - loss: 0.9477 - accuracy: 0.2990 - val_loss: 2.7932 - val_accuracy: 0.1699\n",
      "Epoch 392/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9405 - accuracy: 0.3002 - val_loss: 2.7933 - val_accuracy: 0.1699\n",
      "Epoch 393/400\n",
      "25/25 [==============================] - 2s 96ms/step - loss: 0.9361 - accuracy: 0.3003 - val_loss: 2.8237 - val_accuracy: 0.1703\n",
      "Epoch 394/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9316 - accuracy: 0.3013 - val_loss: 2.8780 - val_accuracy: 0.1703\n",
      "Epoch 395/400\n",
      "25/25 [==============================] - 1s 39ms/step - loss: 0.9300 - accuracy: 0.3018 - val_loss: 2.9357 - val_accuracy: 0.1711\n",
      "Epoch 396/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9330 - accuracy: 0.3012 - val_loss: 2.9577 - val_accuracy: 0.1691\n",
      "Epoch 397/400\n",
      "25/25 [==============================] - 1s 40ms/step - loss: 0.9367 - accuracy: 0.3013 - val_loss: 2.9000 - val_accuracy: 0.1691\n",
      "Epoch 398/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9355 - accuracy: 0.3011 - val_loss: 2.8137 - val_accuracy: 0.1688\n",
      "Epoch 399/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9332 - accuracy: 0.3008 - val_loss: 2.7819 - val_accuracy: 0.1688\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 400/400\n",
      "25/25 [==============================] - 1s 43ms/step - loss: 0.9381 - accuracy: 0.3006 - val_loss: 2.8126 - val_accuracy: 0.1711\n"
     ]
    },
    {
     "data": {
      "image/png": "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EoGle3cznt+KFaZ5+jPPmLqpTz814wB+/rmZpn7aNDNH1ZdftnWKhRCtRAKUCExKwRlnmMYTr74KFRWwdKkZlPa77+DFF02R36RJJucluSlRz/jx4/eb9uIf//gHN93U9FR148ePp67ry6RJkygtLd1vm0cffdTfl6kpc+bMYd26df73Dz/8MPPmzTuE1B/YbbfdRkpKSoNRJ45VEqBE+2O1wu9/D6tXw9VXw6OPmqK/3Ny2TpkIEFOnTmX27NkN1s2ePZupU6c2a/8vvviCmJiYwzr3vgHqscce45RTTjmsY+3L6/Xy8ccf07lzZxYsWNAix2zMkXRcbkkSoET7ZbOZUdSfeWbvwLTvviu5KcGFF17IZ599Rm1tLQA7duxgz549nHDCCdx4440MGzaMAQMG8MgjjzS6f1paGoWFhQA88cQT9OnTh1NOOcU/JQfQ6JQXP//8M3PnzuXuu+8mIyODrVu3Mm3aND744AMAvv32W4YMGcKgQYOYPn26P31paWk88sgjZGZmMmjQIDY00RDo+++/Z+DAgdx4443MmjXLv76xaTYA3nzzTQYPHkx6ejpXXnklQIP0AERERABmmpEJEyZw2WWXMWjQIADOP/98hg4dyoABA3j55Zf9+3z11VdkZmaSnp7OxIkT8Xq99OrVi4KCAsAE0p49e/rv4eGSflCifbNYTDHg2WebSRMvvxy++MI0opBRKgLC7bfDypUte8yMDPjHP5r+PD4+nhEjRvDVV19x3nnnMXv2bC655BKUUjzxxBPExcXh8XiYOHEiq1evZvDgwY0eZ9myZcyePZsVK1bgdrvJzMxk6NChAEyePLnRKS/OPfdczj77bC688MIGx6qpqWHatGl8++239O7dm6uuuooXXniB22+/HYCEhASWL1/O888/z7PPPsurr766X3pmzZrF1KlTOe+88/jTn/6Ey+UiODi40Wk21q5dyxNPPMHChQtJSEjwT/VxIIsXL2bNmjV069YNgJkzZxIXF0d1dTXDhw9nypQpeL1errvuOhYsWEC3bt0oLi7GYrFwxRVX8M4773D77bf7xydMSEg46DkPRHJQ4tjQty/89BM88gi88w5cd51MnHicq1/MV79477333iMzM5MhQ4awdu3aBsVx+/rxxx+54IILCAsLIyoqinPPPdf/2Zo1axg3bhyDBg3inXfe8Y9715SN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adOmTWPOnDmkp6fzxhtvMH/+/AMe52CDItRN63EoU3o0dczY2FhWrVrF119/zb///W/ee+89Zs6cyeeff86CBQuYO3cujz/+OGvXrg3oQCU5KCGEKb475RR48UVYtgwcDpNLKiqC//7XFP2ddRY8/bRp0h4SYvZ76inTYfjKK82wTYdDa9i2zQQpmw127GiRnFRERATjx49n+vTp/txTeXk54eHhREdHk5eXx5dffnnAY5x44ol8/PHHVFdXU1FRwaeffur/rKKiguTkZFwuF++8845/fWRkJBUVFfsdq2/fvuzYsYMtW7YA8NZbb3HSSScd0TWOHDmSH374gcLCQjweD7NmzeKkk06isLAQr9fLlClTePzxx1m+fDler5esrCwmTJjA008/TWlpKZWVLVv02tICN3QKIdqOxQJhYQffLiTEtAY880yTg5o9e+/sws1VVASVlZCWZoZ62rwZyspMg44jNHXqVCZPnuwv6ktPT2fIkCEMGDCA7t27M3bs2APun5mZySWXXEJGRgZdu3Zl3Lhx/s8ef/xxRo4cSdeuXRk0aJA/KF166aVcd911zJgxw984AsBms/H6669z0UUX4Xa7GT58ODfccMMhXc+3337bYDbf999/nyeffJIJEyagtWbSpEmcd955rFq1imuuuQavL9A/+eSTeDwerrjiCsrKytBac8cddxATE3NI5z/aZCw+IcSRKy83QerXX+Gqq1h/6630S083ge5AnE7T0TgkxIx2AbB6tenj5aurEceWQxmLT3JQQogjFxUFX31l+mG99pqZon71atOoIizMtPILDTU5JK/X1G9VVJjhmjwe6NJl7ziEiYlm2KbqahOoxHFLApQQomVERsKMGfCXv5hJFaOjTT1WU82ZlTKBrVMnM4FjncREMxXJ7t3Qo8fBB9AVxywJUEKIlmW3m1xTt27mfV2Oyek004RYLCYnFR7eeBFgcLAJWtnZpj4qOdnkxCRQHXckQAkhWoXW2jTRtlhM0DqU4roOHUxAysmBjRtNHVV0tGn2HhGxN+jV1kJQkFlnte5/HKfTNMIIDjZDOh2sTky0qkNt8yABSgjR4mw2G0VFRcTHxzfZj+iAlDJBKjHR1FOVlppAU1DQ9PZRUSaAhYeb/lR5eaaIsc6ePSY3Fhtrglogq6ufS01tPPC2Q1prioqKsO07UskBBPhvSQjR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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "report_dir_path = './reports'\n",
    "model_dir_path = './models'\n",
    "\n",
    "if not os.path.exists(report_dir_path):\n",
    "    os.mkdir(report_dir_path)\n",
    "    \n",
    "if not os.path.exists(model_dir_path):\n",
    "    os.mkdir(model_dir_path)\n",
    "\n",
    "summarizer = Seq2SeqSummarizer(config)\n",
    "Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, Y, test_size=0.1, random_state=42)#分割数据集\n",
    "\n",
    "print('training size: ', len(Xtrain))\n",
    "print('testing size: ', len(Xtest))\n",
    "\n",
    "print('start fitting ...')\n",
    "history = summarizer.fit(Xtrain, Ytrain, Xtest, Ytest, epochs=USER_EPOCHS)\n",
    "\n",
    "#绘出训练过程\n",
    "history_plot_file_path = report_dir_path + '/' + Seq2SeqSummarizer.model_name + '-history.png'\n",
    "plot_and_save_history(history, summarizer.model_name, history_plot_file_path, metrics={'loss', 'acc'})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "## 测试"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    " ### 加载模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T15:35:19.471124Z",
     "start_time": "2022-05-09T15:35:14.992481Z"
    },
    "hidden": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "model_dir_path = './models'\n",
    "config = np.load(Seq2SeqSummarizer.get_config_file_path(model_dir_path=model_dir_path), allow_pickle=True).item()\n",
    "\n",
    "summarizer = Seq2SeqSummarizer(config)\n",
    "summarizer.load_weights(weight_file_path=Seq2SeqSummarizer.get_weight_file_path(model_dir_path=model_dir_path),\n",
    "                       decoder_weight_file_path=Seq2SeqSummarizer.get_decoder_weight_file_path(model_dir_path=model_dir_path)\n",
    "                       )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "### 随机文本库预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T15:35:37.935577Z",
     "start_time": "2022-05-09T15:35:33.812796Z"
    },
    "hidden": true,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始预测...\n",
      "随机问题:  我 不想 去\n",
      "机器人回复:  那 真是 太好了 内 一下 喔\n",
      "文本库原回复:  为 什么 不想 去 呢\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  可是 我 没 有 伴\n",
      "机器人回复:  可以 问问 看 朋友 或是 家人 的 意愿\n",
      "文本库原回复:  可以 问问 看 朋友 或是 家人 的 意愿 呀\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  对 呀 感觉 很励 志\n",
      "机器人回复:  那 就 忘记 路上 这份 喔\n",
      "文本库原回复:  可以 和 大家 分享 这份 喜悦 唷\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  玩笑\n",
      "机器人回复:  好 的 帮 你 关闭\n",
      "文本库原回复:  你 什么 时候 过 马路 和 草莓 你 得到 了 什么\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  国庆节 连假 要 去 哪 玩\n",
      "机器人回复:  可以 出去 家人 或 朋友 出去 买来 吃 或是 在家\n",
      "文本库原回复:  可以 出去 旅游 或 跟 朋友 出去 聚餐 或是 在家 好好 休息 做些 休闲 娱乐\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  我 好 害怕\n",
      "机器人回复:  好 的 好喝 音乐\n",
      "文本库原回复:  你 看 起来 是 开心 的 是不是 因为 你 把 害怕 的 事藏 在 心里 了 呢\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  复杂 优于 晦涩\n",
      "机器人回复:  你 似乎 很 熟悉\n",
      "文本库原回复:  做 也许 好过 不 做\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  我 最近 都 有 做 瑜珈 唷\n",
      "机器人回复:  那 真是 太好了\n",
      "文本库原回复:  不错 唷 训练 身体 的 柔 软度\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  好热\n",
      "机器人回复:  那要 多 穿衣服 喔 需要 帮 你 电暖炉 吗\n",
      "文本库原回复:  要 帮 你 打开 电风扇 还是 冷气\n",
      "==================================================================================================== \n",
      "\n",
      "随机问题:  我过 得 很 幸福\n",
      "机器人回复:  可以 帮 你 的\n",
      "文本库原回复:  为 什么 呢\n",
      "==================================================================================================== \n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('开始预测...')\n",
    "for i in np.random.permutation(np.arange(len(X)))[0:10]:#随机在文本库中挑选语句\n",
    "    x = X[i]\n",
    "    actual_response = Y[i]\n",
    "    response = summarizer.summarize(x)\n",
    "    print('随机问题: ', x)\n",
    "    print('机器人回复: ', response)\n",
    "    print('文本库原回复: ', actual_response)\n",
    "    print('='*100, '\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true,
    "hidden": true
   },
   "source": [
    "### 单句预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-06T10:03:27.461581Z",
     "start_time": "2022-05-06T10:03:27.453602Z"
    },
    "hidden": true
   },
   "outputs": [],
   "source": [
    "import jieba\n",
    "#分词\n",
    "def segment_one_sentence(sentence):\n",
    "    sentence = sentence.strip()\n",
    "    seg_list = jieba.cut(sentence)\n",
    "\n",
    "    segments = ''\n",
    "    for word in seg_list:\n",
    "        segments = segments + ' ' + word\n",
    "        \n",
    "    return segments"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-06T10:03:33.124777Z",
     "start_time": "2022-05-06T10:03:32.614603Z"
    },
    "hidden": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你输入的内容:  看看 你\n",
      "机器人的回复: 是 啊 伤心 启示录 我\n"
     ]
    }
   ],
   "source": [
    "#单句输入\n",
    "input_X = '看看你'\n",
    "input_X = segment_one_sentence(input_X)\n",
    "\n",
    "print('你输入的内容:', input_X)\n",
    "print('机器人的回复:', summarizer.summarize(input_X))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# CNN模型（判别器）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T08:02:56.697797Z",
     "start_time": "2022-05-10T08:02:56.689780Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "pretrained_discriminator_file = './models/discriminator.h5'\n",
    "dis_filter_sizes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20]\n",
    "dis_num_filters = [100, 200, 200, 200, 200, 100, 100, 100, 100, 100, 160, 160]\n",
    "num_batches = (len(X) // DEFAULT_BATCH_SIZE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "## 生成辨别器数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T08:02:57.759894Z",
     "start_time": "2022-05-10T08:02:57.724246Z"
    },
    "code_folding": [],
    "hidden": true
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'summarizer' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_15452/1983215069.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     13\u001b[0m     \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msavetxt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'./discridata/data.txt'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msummarizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtokenize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdelimiter\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m' '\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfmt\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'%i'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     14\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 15\u001b[1;33m \u001b[0mPredata\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_15452/1983215069.py\u001b[0m in \u001b[0;36mPredata\u001b[1;34m()\u001b[0m\n\u001b[0;32m      6\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpermutation\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mX\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[0mDEFAULT_BATCH_SIZE\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;31m#随机在文本库中挑选语句\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      7\u001b[0m             \u001b[0mactual_response\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mY\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m             \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msummarizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msummarize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mX\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      9\u001b[0m             \u001b[1;31m#附加\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m             \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mactual_response\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'summarizer' is not defined"
     ]
    }
   ],
   "source": [
    "def Predata():\n",
    "    #存储方便调用\n",
    "    #原始文本\n",
    "    data = []\n",
    "    for _ in range(num_batches):\n",
    "        for i in np.random.permutation(np.arange(len(X)))[0:DEFAULT_BATCH_SIZE]:#随机在文本库中挑选语句\n",
    "            actual_response = Y[i]\n",
    "            response = summarizer.summarize(X[i])\n",
    "            #附加\n",
    "            data.append(actual_response)\n",
    "            data.append(response)\n",
    "    #返回序列化数据\n",
    "    np.savetxt('./discridata/data.txt', summarizer.tokenize(data), delimiter=' ', fmt='%i')\n",
    "\n",
    "Predata()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读取辨别器数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T07:57:20.254932Z",
     "start_time": "2022-05-10T07:57:20.095712Z"
    }
   },
   "outputs": [],
   "source": [
    "discridata = []\n",
    "labels = []\n",
    "with open(os.getcwd() + '/discridata/data.txt') as fin:\n",
    "    for line in fin:\n",
    "        line = line.strip().split()\n",
    "        #将读取的数据转为int类型 否则无法送入模型\n",
    "        parse_line = [int(x) for x in line]\n",
    "        if len(parse_line) == 20:\n",
    "            discridata.append(parse_line)\n",
    "        #labels.append([1, 0])\n",
    "    for i in range(int(len(discridata)/2)):\n",
    "        labels.append([0, 1])\n",
    "        labels.append([1, 0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义CNN模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T08:03:08.777379Z",
     "start_time": "2022-05-10T08:03:08.761838Z"
    }
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "\n",
    "#Highway神经网络模型https://arxiv.org/pdf/1505.00387.pdf\n",
    "class Highway(tf.keras.models.Model):\n",
    "    def __init__(self, **kwargs):\n",
    "        super(Highway, self).__init__(**kwargs)\n",
    "\n",
    "    def build(self, input_shape):\n",
    "        output_dim = input_shape[-1]\n",
    "        self.dense_g = Dense(output_dim, activation=\"relu\")\n",
    "        self.dense_t = Dense(output_dim, activation=\"sigmoid\")\n",
    "\n",
    "    def call(self, input_tensor, training=False):\n",
    "        g = self.dense_g(input_tensor, training=training)\n",
    "        t = self.dense_t(input_tensor, training=training)\n",
    "        o = t * g + (1. - t) * input_tensor\n",
    "        return o\n",
    "\n",
    "\n",
    "class Discriminator:\n",
    "    #使用CNN作为分类\n",
    "    def __init__(\n",
    "            self, sequence_length, num_classes, vocab_size,\n",
    "            embedding_size, filter_sizes, num_filters, dropout_keep_prob, l2_reg_lambda=0.0):\n",
    "        self.sequence_length = sequence_length#序列长度\n",
    "        self.num_classes = num_classes#分类\n",
    "        self.vocab_size = vocab_size#词汇表大小\n",
    "        self.embedding_size = embedding_size#嵌入层\n",
    "        #模型输入\n",
    "        layer_input = Input((sequence_length,), dtype=tf.int32)\n",
    "        layer_emb = Embedding(vocab_size, embedding_size,\n",
    "                              embeddings_initializer=tf.random_uniform_initializer(-1.0, 1.0))(layer_input)\n",
    "\n",
    "        pooled_outputs = []\n",
    "        for filter_size, num_filter in zip(filter_sizes, num_filters):#滤波器大小、数量\n",
    "            x = Conv1D(num_filter, filter_size)(layer_emb)#卷积\n",
    "            x = MaxPool1D(sequence_length - filter_size + 1)(x)#池化\n",
    "            pooled_outputs.append(x)\n",
    "        #合并输入\n",
    "        x = Concatenate()(pooled_outputs)\n",
    "        #打平\n",
    "        x = Flatten()(x)\n",
    "        x = Highway()(x)\n",
    "        #随机失活\n",
    "        x = Dropout(1.0 - dropout_keep_prob)(x)\n",
    "        layer_output = Dense(num_classes,\n",
    "                             kernel_regularizer=tf.keras.regularizers.l2(l2_reg_lambda),\n",
    "                             bias_regularizer=tf.keras.regularizers.l2(l2_reg_lambda),\n",
    "                             activation=\"softmax\")(x)\n",
    "\n",
    "        self.d_model = Model(layer_input, layer_output)\n",
    "        plot_model(self.d_model, to_file='./reports/dis_model.png',show_shapes=True)\n",
    "        d_optimizer = tf.keras.optimizers.Adam(1e-4)\n",
    "        self.d_model.compile(optimizer=d_optimizer, loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])\n",
    "\n",
    "    def train(self, dataset, num_epochs, num_steps, **kwargs):\n",
    "        return self.d_model.fit(dataset.repeat(num_epochs), verbose=1, epochs=num_epochs, steps_per_epoch=num_steps,\n",
    "                                **kwargs)\n",
    "\n",
    "    def save(self, filename):\n",
    "        self.d_model.save_weights(filename, save_format=\"h5\")\n",
    "\n",
    "    def load(self, filename):\n",
    "        self.d_model.load_weights(filename)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-10T08:03:10.707388Z",
     "start_time": "2022-05-10T08:03:09.391584Z"
    }
   },
   "outputs": [],
   "source": [
    "discriminator = Discriminator(sequence_length=MAX_TARGET_SEQ_LENGTH, num_classes=2, vocab_size=MAX_TARGET_VOCAB_SIZE,\n",
    "                                  embedding_size=HIDDEN_UNITS,\n",
    "                                  filter_sizes=dis_filter_sizes, num_filters=dis_num_filters,\n",
    "                                  dropout_keep_prob=0.75,\n",
    "                                  l2_reg_lambda=0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T14:30:12.777104Z",
     "start_time": "2022-05-09T14:29:41.199186Z"
    },
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始预训练判别器\n",
      "Epoch 1/20\n",
      "56/56 [==============================] - 5s 23ms/step - loss: 1.2408 - accuracy: 0.7779\n",
      "Epoch 2/20\n",
      "56/56 [==============================] - 1s 22ms/step - loss: 0.9827 - accuracy: 0.8758\n",
      "Epoch 3/20\n",
      "56/56 [==============================] - 1s 23ms/step - loss: 0.8735 - accuracy: 0.8943\n",
      "Epoch 4/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.7795 - accuracy: 0.9043\n",
      "Epoch 5/20\n",
      "56/56 [==============================] - 1s 25ms/step - loss: 0.7024 - accuracy: 0.9121\n",
      "Epoch 6/20\n",
      "56/56 [==============================] - 1s 25ms/step - loss: 0.6355 - accuracy: 0.9166\n",
      "Epoch 7/20\n",
      "56/56 [==============================] - 1s 25ms/step - loss: 0.5741 - accuracy: 0.9213\n",
      "Epoch 8/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.5178 - accuracy: 0.9224\n",
      "Epoch 9/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.4685 - accuracy: 0.9275\n",
      "Epoch 10/20\n",
      "56/56 [==============================] - 1s 25ms/step - loss: 0.4246 - accuracy: 0.9291\n",
      "Epoch 11/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.3883 - accuracy: 0.9277\n",
      "Epoch 12/20\n",
      "56/56 [==============================] - 1s 25ms/step - loss: 0.3555 - accuracy: 0.9330\n",
      "Epoch 13/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.3269 - accuracy: 0.9269\n",
      "Epoch 14/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.3019 - accuracy: 0.9283\n",
      "Epoch 15/20\n",
      "56/56 [==============================] - 1s 25ms/step - loss: 0.2824 - accuracy: 0.9305\n",
      "Epoch 16/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.2618 - accuracy: 0.9300\n",
      "Epoch 17/20\n",
      "56/56 [==============================] - 1s 23ms/step - loss: 0.2447 - accuracy: 0.9330\n",
      "Epoch 18/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.2314 - accuracy: 0.9289\n",
      "Epoch 19/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.2171 - accuracy: 0.9342\n",
      "Epoch 20/20\n",
      "56/56 [==============================] - 1s 24ms/step - loss: 0.2085 - accuracy: 0.9319\n",
      "完成预训练判别器...\n"
     ]
    }
   ],
   "source": [
    "#初始化辨别器模型\n",
    "discriminator = Discriminator(sequence_length=MAX_TARGET_SEQ_LENGTH, num_classes=2, vocab_size=MAX_TARGET_VOCAB_SIZE,\n",
    "                                  embedding_size=HIDDEN_UNITS,\n",
    "                                  filter_sizes=dis_filter_sizes, num_filters=dis_num_filters,\n",
    "                                  dropout_keep_prob=0.75,\n",
    "                                  l2_reg_lambda=0.2)\n",
    "\n",
    "if not os.path.exists(pretrained_discriminator_file):\n",
    "        print('开始预训练判别器')\n",
    "        dis_dataset = tf.data.Dataset.from_tensor_slices((discridata, labels)).batch(DEFAULT_BATCH_SIZE)\n",
    "        #导入原始和生成文本\n",
    "        discriminator.train(dis_dataset, 20, num_batches * 2)\n",
    "        discriminator.save(pretrained_discriminator_file)\n",
    "        print('完成预训练判别器...')\n",
    "else:\n",
    "    discriminator.load(pretrained_discriminator_file)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 对抗训练"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 计算reward的采样过程"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T14:31:47.498039Z",
     "start_time": "2022-05-09T14:31:47.487067Z"
    },
    "code_folding": [
     14
    ]
   },
   "outputs": [],
   "source": [
    "class ROLLOUT:\n",
    "    def __init__(self, generate, update_rate):\n",
    "        self.sequence_length = generate.num_target_tokens\n",
    "        self.generate = generate\n",
    "        \n",
    "    def get_reward(self, input_x, labels,rollout_num, discriminator):\n",
    "        # input_x表示需要打分的序列\n",
    "        # rollout_num：采样的次数，即将多少个reward取平均\n",
    "        rewards = []\n",
    "        labels = summarizer.tokenize(labels)\n",
    "        for i in range(rollout_num):\n",
    "            #生成一批样本\n",
    "            samples = []\n",
    "            for j in range(len(input_x)):\n",
    "                samples.append(summarizer.summarize(input_x[j]))\n",
    "            #将文本转为向量\n",
    "            samples = summarizer.tokenize(samples)\n",
    "            for given_num in tf.range(1, self.sequence_length):\n",
    "                ypred_for_auc = discriminator.d_model(samples).numpy()#判别器给每个句子打分，作为reward\n",
    "                ypred = ypred_for_auc[:, 1]\n",
    "                if i == 0:\n",
    "                    rewards.append(ypred)\n",
    "                else:\n",
    "                    rewards[given_num - 1] += ypred\n",
    "            #二分类，第一个数为该样本为假样本的概率，第二个数为真样本的概率\n",
    "            ypred_for_auc = discriminator.d_model(labels).numpy()\n",
    "            ypred = ypred_for_auc[:, 1]\n",
    "            if i == 0:\n",
    "                rewards.append(ypred)\n",
    "            else:\n",
    "                rewards[self.sequence_length - 1] += ypred\n",
    "            print(\"rewards\",i+1)\n",
    "        rewards = np.transpose(np.array(rewards)) / (1.0 * rollout_num)  # batch_size x seq_length\n",
    "        return rewards"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始对抗训练...\n",
      "Generator 0\n",
      "(64, 20)\n",
      "(64, 20)\n",
      "rewards 1\n",
      "(64, 20)\n",
      "rewards 2\n",
      "(64, 20)\n",
      "rewards 3\n",
      "(64, 20)\n",
      "rewards 4\n",
      "(64, 20)\n",
      "rewards 5\n",
      "(64, 20)\n",
      "rewards 6\n",
      "(64, 20)\n",
      "rewards 7\n",
      "(64, 20)\n",
      "rewards 8\n",
      "(64, 20)\n",
      "rewards 9\n",
      "(64, 20)\n",
      "rewards 10\n",
      "(64, 20)\n",
      "rewards 11\n",
      "(64, 20)\n",
      "rewards 12\n",
      "(64, 20)\n",
      "rewards 13\n",
      "(64, 20)\n",
      "rewards 14\n",
      "(64, 20)\n",
      "rewards 15\n",
      "(64, 20)\n",
      "rewards 16\n",
      "(64, 20)\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "in user code:\n\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 1021, in train_function  *\n        return step_function(self, iterator)\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 1010, in step_function  **\n        outputs = model.distribute_strategy.run(run_step, args=(data,))\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 1000, in run_step  **\n        outputs = model.train_step(data)\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 859, in train_step\n        y_pred = self(x, training=True)\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\utils\\traceback_utils.py\", line 67, in error_handler\n        raise e.with_traceback(filtered_tb) from None\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\input_spec.py\", line 200, in assert_input_compatibility\n        raise ValueError(f'Layer \"{layer_name}\" expects {len(input_spec)} input(s),'\n\n    ValueError: Layer \"model_37\" expects 2 input(s), but it received 1 input tensors. Inputs received: [<tf.Tensor 'IteratorGetNext:0' shape=(64, 20) dtype=int32>]\n",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_16916/697306862.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     14\u001b[0m         \u001b[1;31m#序列化\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m         \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msummarizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtokenize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m         \u001b[0msummarizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtrain_step\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mlabels\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mrewards\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     18\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Discriminator\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepoch\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_16916/3314672526.py\u001b[0m in \u001b[0;36mtrain_step\u001b[1;34m(self, x, y, rewards)\u001b[0m\n\u001b[0;32m    119\u001b[0m     \u001b[1;31m#一批次训练\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    120\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mtrain_step\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mrewards\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 121\u001b[1;33m         train_loss = self.model.train_on_batch(\n\u001b[0m\u001b[0;32m    122\u001b[0m             \u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    123\u001b[0m             \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpad\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"constant\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mconstant_values\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\u001b[0m in \u001b[0;36mtrain_on_batch\u001b[1;34m(self, x, y, sample_weight, class_weight, reset_metrics, return_dict)\u001b[0m\n\u001b[0;32m   2091\u001b[0m                                                     class_weight)\n\u001b[0;32m   2092\u001b[0m       \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtrain_function\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmake_train_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2093\u001b[1;33m       \u001b[0mlogs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtrain_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0miterator\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   2094\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2095\u001b[0m     \u001b[0mlogs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtf_utils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msync_to_numpy_or_python_type\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlogs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\tensorflow\\python\\util\\traceback_utils.py\u001b[0m in \u001b[0;36merror_handler\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m    151\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    152\u001b[0m       \u001b[0mfiltered_tb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_process_traceback_frames\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__traceback__\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 153\u001b[1;33m       \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfiltered_tb\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    154\u001b[0m     \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    155\u001b[0m       \u001b[1;32mdel\u001b[0m \u001b[0mfiltered_tb\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\ProgramData\\Anaconda3\\lib\\site-packages\\tensorflow\\python\\framework\\func_graph.py\u001b[0m in \u001b[0;36mautograph_handler\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m   1145\u001b[0m           \u001b[1;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m  \u001b[1;31m# pylint:disable=broad-except\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1146\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"ag_error_metadata\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1147\u001b[1;33m               \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mag_error_metadata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_exception\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1148\u001b[0m             \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1149\u001b[0m               \u001b[1;32mraise\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: in user code:\n\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 1021, in train_function  *\n        return step_function(self, iterator)\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 1010, in step_function  **\n        outputs = model.distribute_strategy.run(run_step, args=(data,))\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 1000, in run_step  **\n        outputs = model.train_step(data)\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\", line 859, in train_step\n        y_pred = self(x, training=True)\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\utils\\traceback_utils.py\", line 67, in error_handler\n        raise e.with_traceback(filtered_tb) from None\n    File \"c:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\input_spec.py\", line 200, in assert_input_compatibility\n        raise ValueError(f'Layer \"{layer_name}\" expects {len(input_spec)} input(s),'\n\n    ValueError: Layer \"model_37\" expects 2 input(s), but it received 1 input tensors. Inputs received: [<tf.Tensor 'IteratorGetNext:0' shape=(64, 20) dtype=int32>]\n"
     ]
    }
   ],
   "source": [
    "rollout = ROLLOUT(summarizer, 0.8)\n",
    "print('开始对抗训练...')\n",
    "for epoch in range(10):\n",
    "    print(\"Generator\", epoch)\n",
    "    for it in range(1):\n",
    "        data = []\n",
    "        labels = []\n",
    "        for i in np.random.permutation(np.arange(len(X)))[0:DEFAULT_BATCH_SIZE]:#随机在文本库中挑选语句\n",
    "            data.append(X[i])\n",
    "            labels.append(Y[i])\n",
    "        labels = summarizer.tokenize(labels)\n",
    "        #计算\n",
    "        rewards = rollout.get_reward(data, labels,16, discriminator)\n",
    "        #序列化\n",
    "        data = summarizer.tokenize(data)\n",
    "        summarizer.train_step(data,labels,rewards)\n",
    "\n",
    "    print(\"Discriminator\", epoch)\n",
    "    for _ in range(5):\n",
    "        #生成一批\n",
    "        Predata()\n",
    "        #读取数据\n",
    "        discridata = []\n",
    "        labels = []\n",
    "        with open(os.getcwd() + '/discridata/data.txt') as fin:\n",
    "            for line in fin:\n",
    "                line = line.strip().split()\n",
    "                #将读取的数据转为int类型 否则无法送入模型\n",
    "                parse_line = [int(x) for x in line]\n",
    "                discridata.append(parse_line)\n",
    "            for i in range(int(len(discridata)/2)):\n",
    "                labels.append([0, 1])\n",
    "                labels.append([1, 0])\n",
    "\n",
    "        dis_dataset = tf.data.Dataset.from_tensor_slices((discridata, labels)).shuffle(len(discridata)).batch(DEFAULT_BATCH_SIZE)\n",
    "        discriminator.train(dis_dataset, 20, num_batches * 2)\n",
    "summarizer.model.save_weights(Seq2SeqSummarizer.get_weight_file_path('./models'))\n",
    "discriminator.save(pretrained_discriminator_file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T14:47:37.047437Z",
     "start_time": "2022-05-09T14:31:58.914079Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(64, 14)\n",
      "(64,)\n",
      "(64, 20)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\taki\\AppData\\Local\\Temp/ipykernel_7864/2783105689.py:142: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n",
      "  temp = np.array(temp)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(64, 20)\n",
      "rewards 1\n",
      "(64, 20)\n",
      "rewards 2\n",
      "(64, 20)\n",
      "rewards 3\n",
      "(64, 20)\n",
      "rewards 4\n",
      "(64, 20)\n",
      "rewards 5\n",
      "(64, 20)\n",
      "rewards 6\n",
      "(64, 20)\n",
      "rewards 7\n",
      "(64, 20)\n",
      "rewards 8\n",
      "(64, 20)\n",
      "rewards 9\n",
      "(64, 20)\n",
      "rewards 10\n",
      "(64, 20)\n",
      "rewards 11\n",
      "(64, 20)\n",
      "rewards 12\n",
      "(64, 20)\n",
      "rewards 13\n",
      "(64, 20)\n",
      "rewards 14\n",
      "(64, 20)\n",
      "rewards 15\n",
      "(64, 20)\n",
      "rewards 16\n"
     ]
    }
   ],
   "source": [
    "rollout = ROLLOUT(summarizer, 0.8)\n",
    "data = []\n",
    "labels = []\n",
    "for i in np.random.permutation(np.arange(len(X)))[0:DEFAULT_BATCH_SIZE]:#随机在文本库中挑选语句\n",
    "    data.append(X[i])\n",
    "    labels.append(Y[i])\n",
    "gen_data = summarizer.transform_input_text(data)\n",
    "gen_labels = summarizer.transform_target_encoding(labels)\n",
    "#计算\n",
    "rewards = rollout.get_reward(data, labels,16, discriminator)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T15:32:43.114623Z",
     "start_time": "2022-05-09T15:32:43.103659Z"
    },
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "def generate_batch2(x_samples, y_samples, batch_size = 64,num_batches=1):\n",
    "        self = summarizer\n",
    "        start = 0\n",
    "        end = batch_size\n",
    "        decoder_target_data_batch = np.zeros(shape=(batch_size, summarizer.max_target_seq_length, summarizer.num_target_tokens))\n",
    "        decoder_input_data_batch = np.zeros(shape=(batch_size, summarizer.max_target_seq_length, summarizer.num_target_tokens))\n",
    "        for lineIdx, target_words in enumerate(y_samples[start:end]):\n",
    "            for idx, w in enumerate(target_words):\n",
    "                w2idx = 0  # default [UNK]\n",
    "                if w in self.target_word2idx:\n",
    "                    w2idx = self.target_word2idx[w]\n",
    "                if w2idx != 0:\n",
    "                    decoder_input_data_batch[lineIdx, idx, w2idx] = 1\n",
    "                    if idx > 0:\n",
    "                        decoder_target_data_batch[lineIdx, idx - 1, w2idx] = 1\n",
    "        return decoder_input_data_batch, decoder_target_data_batch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T16:09:30.992318Z",
     "start_time": "2022-05-09T16:09:30.984348Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "64"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(rewards)\n",
    "#改造SUMMER"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T15:33:04.586689Z",
     "start_time": "2022-05-09T15:33:04.573685Z"
    }
   },
   "outputs": [],
   "source": [
    "x,y= generate_batch2(gen_data,gen_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T15:50:34.495108Z",
     "start_time": "2022-05-09T15:50:34.472164Z"
    }
   },
   "outputs": [],
   "source": [
    "summarizer.decoder_model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-05-09T15:50:38.175457Z",
     "start_time": "2022-05-09T15:50:38.137554Z"
    }
   },
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'str' object has no attribute 'shape'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_7864/479118322.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m summarizer.decoder_model.train_on_batch(\n\u001b[0m\u001b[0;32m      2\u001b[0m             \u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mrewards\u001b[0m \u001b[1;33m*\u001b[0m \u001b[0mDEFAULT_BATCH_SIZE\u001b[0m \u001b[1;33m*\u001b[0m \u001b[0mMAX_TARGET_SEQ_LENGTH\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m         )\n",
      "\u001b[1;32mC:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\training.py\u001b[0m in \u001b[0;36mtrain_on_batch\u001b[1;34m(self, x, y, sample_weight, class_weight, reset_metrics, return_dict)\u001b[0m\n\u001b[0;32m   2087\u001b[0m     \u001b[1;32mwith\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdistribute_strategy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mscope\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0;31m \u001b[0m\u001b[0;31m\\\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2088\u001b[0m          \u001b[0mtraining_utils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mRespectCompiledTrainableState\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2089\u001b[1;33m       iterator = data_adapter.single_batch_iterator(self.distribute_strategy, x,\n\u001b[0m\u001b[0;32m   2090\u001b[0m                                                     \u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msample_weight\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2091\u001b[0m                                                     class_weight)\n",
      "\u001b[1;32mC:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\data_adapter.py\u001b[0m in \u001b[0;36msingle_batch_iterator\u001b[1;34m(strategy, x, y, sample_weight, class_weight)\u001b[0m\n\u001b[0;32m   1634\u001b[0m     \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msample_weight\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1635\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1636\u001b[1;33m   \u001b[0m_check_data_cardinality\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1637\u001b[0m   \u001b[0mdataset\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mDataset\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfrom_tensors\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1638\u001b[0m   \u001b[1;32mif\u001b[0m \u001b[0mclass_weight\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mC:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\data_adapter.py\u001b[0m in \u001b[0;36m_check_data_cardinality\u001b[1;34m(data)\u001b[0m\n\u001b[0;32m   1643\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1644\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_check_data_cardinality\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1645\u001b[1;33m   \u001b[0mnum_samples\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mtf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mflatten\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1646\u001b[0m   \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum_samples\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1647\u001b[0m     \u001b[0mmsg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m\"Data cardinality is ambiguous:\\n\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mC:\\ProgramData\\Anaconda3\\lib\\site-packages\\keras\\engine\\data_adapter.py\u001b[0m in \u001b[0;36m<genexpr>\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m   1643\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1644\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_check_data_cardinality\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1645\u001b[1;33m   \u001b[0mnum_samples\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mtf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mflatten\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1646\u001b[0m   \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum_samples\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1647\u001b[0m     \u001b[0mmsg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m\"Data cardinality is ambiguous:\\n\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'str' object has no attribute 'shape'"
     ]
    }
   ],
   "source": [
    "summarizer.decoder_model.train_on_batch(\n",
    "            x,y,rewards * DEFAULT_BATCH_SIZE * MAX_TARGET_SEQ_LENGTH\n",
    "        )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  },
  "vscode": {
   "interpreter": {
    "hash": "ad2bdc8ecc057115af97d19610ffacc2b4e99fae6737bb82f5d7fb13d2f2c186"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
